[evolution-exchange] Bug #590251 - Let it compile and run with eds/evo master



commit c1516110e34d4858b480f4336b560329f0902ef6
Author: Milan Crha <mcrha redhat com>
Date:   Fri Oct 2 12:32:06 2009 +0200

    Bug #590251 - Let it compile and run with eds/evo master

 Makefile.am                                        |   10 +-
 addressbook/Makefile.am                            |    7 +-
 addressbook/e-book-backend-exchange-factory.c      |   72 +-
 addressbook/e-book-backend-exchange-factory.h      |   67 -
 addressbook/e-book-backend-exchange.c              |   42 +-
 addressbook/e-book-backend-gal-factory.c           |   76 -
 addressbook/e-book-backend-gal-factory.h           |   50 -
 addressbook/e-book-backend-gal.c                   |   12 +-
 addressbook/e-book-backend-gal.h                   |    1 -
 autogen.sh                                         |    8 +-
 calendar/Makefile.am                               |    7 +-
 calendar/e-cal-backend-exchange-factory.c          |    9 +-
 calendar/e-cal-backend-exchange.c                  |    9 +-
 camel/Makefile.am                                  |   20 +-
 camel/camel-exchange-folder.c                      |  128 +-
 camel/camel-exchange-folder.h                      |    3 -
 camel/camel-exchange-journal.c                     |   27 +-
 camel/camel-exchange-search.c                      |   10 +-
 camel/camel-exchange-store.c                       |  482 +--
 camel/camel-exchange-store.h                       |    6 +-
 camel/camel-exchange-summary.c                     |   28 +-
 camel/camel-exchange-transport.c                   |   26 +-
 .../camel-exchange-utils.c                         | 4025 ++++++++++----------
 camel/camel-exchange-utils.h                       |  141 +
 camel/camel-stub-constants.h                       |   97 -
 camel/camel-stub-marshal.c                         |  489 ---
 camel/camel-stub-marshal.h                         |   47 -
 camel/camel-stub.c                                 |  635 ---
 camel/camel-stub.h                                 |   56 -
 {mail => camel}/mail-utils.c                       |   16 +-
 {mail => camel}/mail-utils.h                       |    4 +
 configure.ac                                       |    5 +-
 mail/Makefile.am                                   |   26 -
 mail/mail-stub-exchange.h                          |   47 -
 mail/mail-stub-listener.c                          |  216 --
 mail/mail-stub-listener.h                          |   45 -
 mail/mail-stub.c                                   |  787 ----
 mail/mail-stub.h                                   |  111 -
 po/POTFILES.in                                     |   17 +-
 po/POTFILES.skip                                   |    5 -
 .../GNOME_Evolution_Exchange_Storage.server.in.in  |   41 -
 storage/Makefile.am                                |  115 -
 storage/exchange-component.c                       |  515 ---
 storage/exchange-component.h                       |   56 -
 storage/exchange-config-listener.h                 |   61 -
 storage/exchange-migrate.c                         |  517 ---
 storage/exchange-migrate.h                         |   11 -
 storage/exchange-storage.c                         |  384 --
 storage/exchange-storage.h                         |   43 -
 storage/main.c                                     |  188 -
 tools/Makefile.am                                  |   78 +
 {storage => tools}/connector-mini.png              |  Bin 1761 -> 1761 bytes
 {storage => tools}/connector.png                   |  Bin 3338 -> 3338 bytes
 {storage => tools}/exchange-autoconfig-wizard.c    |    2 -
 {storage => tools}/exchange-autoconfig-wizard.h    |    0
 {storage => tools}/exchange-delegates-48.png       |  Bin 3663 -> 3663 bytes
 {storage => tools}/exchange-oof-48.png             |  Bin 3159 -> 3159 bytes
 .../exchange-share-config-listener.c               |  197 +-
 tools/exchange-share-config-listener.h             |   69 +
 {storage => tools}/migr-test.c                     |    0
 {storage => tools}/ximian-connector-setup.c        |    0
 {storage => tools}/ximian-connector.xml            |    0
 62 files changed, 2625 insertions(+), 7521 deletions(-)
---
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/addressbook/Makefile.am b/addressbook/Makefile.am
index 66af3ca..b1e9711 100644
--- a/addressbook/Makefile.am
+++ b/addressbook/Makefile.am
@@ -1,6 +1,5 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir) \
-	-I$(top_srcdir)/storage \
 	-DG_LOG_DOMAIN=\"e-book-backend-exchange\" \
 	$(ADDRESSBOOK_CFLAGS) \
 	$(LIBEXCHANGE_CFLAGS) \
@@ -44,9 +43,6 @@ libebookbackendexchange_la_SOURCES = \
 	e-book-backend-exchange.c \
 	e-book-backend-exchange.h \
 	e-book-backend-exchange-factory.c \
-	e-book-backend-exchange-factory.h \
-	e-book-backend-gal-factory.c \
-	e-book-backend-gal-factory.h \
 	e-book-backend-gal.c \
 	e-book-backend-gal.h
 
@@ -55,7 +51,8 @@ libebookbackendexchange_la_SOURCES += \
 	e-book-backend-db-cache.c \
 	e-book-backend-db-cache.h
 
-libebookbackendexchange_la_LIBADD =  \
+libebookbackendexchange_la_LIBADD =  				\
+	$(top_builddir)/tools/libevolution-exchange-shared.la	\
 	$(DB_LIBS)
 
 libebookbackendexchange_la_LDFLAGS = \
diff --git a/addressbook/e-book-backend-exchange-factory.c b/addressbook/e-book-backend-exchange-factory.c
index c045ecc..aa5afa7 100644
--- a/addressbook/e-book-backend-exchange-factory.c
+++ b/addressbook/e-book-backend-exchange-factory.c
@@ -25,64 +25,26 @@
 #include <string.h>
 
 #include <libebackend/e-data-server-module.h>
-#include "e-book-backend-exchange-factory.h"
-#include "e-book-backend-exchange.h"
-
-static GType exchange_type;
-
-static const gchar *
-book_backend_exchange_factory_get_protocol (EBookBackendFactory *factory)
-{
-	return "exchange";
-}
+#include <libedata-book/e-book-backend-factory.h>
+#include <camel/camel-object.h>
 
-static EBookBackend*
-book_backend_exchange_factory_new_backend (EBookBackendFactory *factory)
-{
-	return e_book_backend_exchange_new ();
-}
-
-static void
-book_backend_exchange_factory_class_init (EBookBackendExchangeFactoryClass *class)
-{
-	EBookBackendFactoryClass *factory_class;
-
-	factory_class = E_BOOK_BACKEND_FACTORY_CLASS (class);
-	factory_class->get_protocol = book_backend_exchange_factory_get_protocol;
-	factory_class->new_backend = book_backend_exchange_factory_new_backend;
-}
-
-GType
-e_book_backend_exchange_factory_get_type (void)
-{
-	return exchange_type;
-}
+#include "e-book-backend-exchange.h"
+#include "e-book-backend-gal.h"
 
-void
-e_book_backend_exchange_factory_register_type (GTypeModule *type_module)
-{
-	static const GTypeInfo type_info = {
-		sizeof (EBookBackendExchangeFactoryClass),
-		(GBaseInitFunc) NULL,
-		(GBaseFinalizeFunc) NULL,
-		(GClassInitFunc)  book_backend_exchange_factory_class_init,
-		(GClassFinalizeFunc) NULL,
-		NULL,  /* class_data */
-		sizeof (EBookBackend),
-		0,     /* n_preallocs */
-		(GInstanceInitFunc) NULL,
-		NULL   /* value_table */
-	};
+E_BOOK_BACKEND_FACTORY_SIMPLE (exchange, Exchange, e_book_backend_exchange_new)
+E_BOOK_BACKEND_FACTORY_SIMPLE (gal, Gal, e_book_backend_gal_new)
 
-	exchange_type = g_type_module_register_type (
-		type_module, E_TYPE_BOOK_BACKEND_FACTORY,
-		"EBookBackendExchangeFactory", &type_info, 0);
-}
+static GType exchange_types[2];
 
 void
 eds_module_initialize (GTypeModule *type_module)
 {
-	e_book_backend_exchange_factory_register_type (type_module);
+	/* to have a camel type initialized properly */
+	camel_type_init ();
+	camel_object_get_type ();
+
+	exchange_types[0] = _exchange_factory_get_type (type_module);
+	exchange_types[1] = _gal_factory_get_type (type_module);
 }
 
 void
@@ -93,10 +55,6 @@ eds_module_shutdown (void)
 void
 eds_module_list_types (const GType **types, gint *num_types)
 {
-	static GType module_types[1];
-
-	module_types[0] = E_TYPE_BOOK_BACKEND_EXCHANGE_FACTORY;
-
-	*types = module_types;
-	*num_types = G_N_ELEMENTS (module_types);
+	*types = exchange_types;
+	*num_types = G_N_ELEMENTS (exchange_types);
 }
diff --git a/addressbook/e-book-backend-exchange.c b/addressbook/e-book-backend-exchange.c
index 1de981b..b6ab7e9 100644
--- a/addressbook/e-book-backend-exchange.c
+++ b/addressbook/e-book-backend-exchange.c
@@ -57,8 +57,9 @@
 #include <exchange-hierarchy.h>
 #include <exchange-esource.h>
 #include <e-folder-exchange.h>
+
+#include "tools/exchange-share-config-listener.h"
 #include "e-book-backend-exchange.h"
-#include "exchange-component.h"
 
 #define DEBUG
 #define d(x)
@@ -691,7 +692,7 @@ e_book_backend_exchange_connect (EBookBackendExchange *be)
 	time_t folder_mtime;
 
 	if (!bepriv->account) {
-		bepriv->account = exchange_component_get_account_for_uri (global_exchange_component, bepriv->exchange_uri);
+		bepriv->account = exchange_share_config_listener_get_account_for_uri (NULL, bepriv->exchange_uri);
 		if (!bepriv->account)
 			return GNOME_Evolution_Addressbook_RepositoryOffline;
 	}
@@ -2278,7 +2279,7 @@ e_book_backend_exchange_start_book_view (EBookBackend  *backend,
 
 	d(printf("ebbe_start_book_view(%p, %p)\n", backend, book_view));
 
-	bonobo_object_ref (book_view);
+	e_data_book_view_ref (book_view);
 	e_data_book_view_notify_status_message (book_view, _("Searching..."));
 
 	switch (bepriv->mode) {
@@ -2319,16 +2320,15 @@ e_book_backend_exchange_start_book_view (EBookBackend  *backend,
 					GNOME_Evolution_Addressbook_Success);
 		if (temp_list)
 			 g_list_free (temp_list);
-		bonobo_object_unref (book_view);
+		e_data_book_view_unref (book_view);
 		return;
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
 
 		if (!be->priv->ctx) {
 			e_book_backend_notify_auth_required (backend);
-			e_data_book_view_notify_complete (book_view,
-						GNOME_Evolution_Addressbook_AuthenticationRequired);
-			bonobo_object_unref (book_view);
+			e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_AuthenticationRequired);
+			e_data_book_view_unref (book_view);
 			return;
 		}
 
@@ -2354,9 +2354,8 @@ e_book_backend_exchange_start_book_view (EBookBackend  *backend,
 		}
 		status = e2k_result_iter_free (iter);
 
-		e_data_book_view_notify_complete (book_view,
-						  http_status_to_pas (status));
-		bonobo_object_unref (book_view);
+		e_data_book_view_notify_complete (book_view, http_status_to_pas (status));
+		e_data_book_view_unref (book_view);
 
 		/* also update the folder list */
 		exchange_account_rescan_tree (bepriv->account);
@@ -2390,9 +2389,14 @@ typedef struct {
 } EBookBackendExchangeChangeContext;
 
 static void
-free_change (gpointer change, gpointer user_data)
+free_change (gpointer data, gpointer user_data)
 {
-	CORBA_free (change);
+	EDataBookChange *change = data;
+
+	if (change) {
+		g_free (change->vcard);
+		g_free (change);
+	}
 }
 
 static gboolean
@@ -2623,7 +2627,7 @@ e_book_backend_exchange_authenticate_user (EBookBackend *backend,
 	EBookBackendExchange *be = E_BOOK_BACKEND_EXCHANGE (backend);
 	EBookBackendExchangePrivate *bepriv = be->priv;
 	ExchangeAccountResult result;
-	ExchangeAccount *account;
+	ExchangeAccount *account = NULL;
 
 	d(printf("ebbe_authenticate_user(%p, %p, %s, %s, %s)\n", backend, book, user, password, auth_method));
 
@@ -2637,7 +2641,7 @@ e_book_backend_exchange_authenticate_user (EBookBackend *backend,
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
 
-		bepriv->account = account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		bepriv->account = account = exchange_share_config_listener_get_account_for_uri (NULL, bepriv->exchange_uri);
 		/* FIXME : Check for failures */
 		if (!(bepriv->ctx = exchange_account_get_context (account))) {
 			exchange_account_set_online (account);
@@ -2801,12 +2805,12 @@ e_book_backend_exchange_remove (EBookBackendSync *backend, EDataBook *book, guin
 	if (int_uri)
 		result = exchange_account_remove_folder (bepriv->account, int_uri);
 	else {
-		ExchangeAccount *account;
+		ExchangeAccount *account = NULL;
 
 		/* internal URI is NULL, mostly the case where folder doesn't exists anymore
 		 * in the server, update the gconf sources.
 		 */
-		account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		account = exchange_share_config_listener_get_account_for_uri (NULL, bepriv->exchange_uri);
 		if (exchange_account_get_context (account)) {
 			remove_folder_esource (account, EXCHANGE_CONTACTS_FOLDER, bepriv->exchange_uri);
 			result = EXCHANGE_ACCOUNT_FOLDER_OK;
@@ -2850,7 +2854,7 @@ e_book_backend_exchange_set_mode (EBookBackend *backend,
 {
 	EBookBackendExchange *be = E_BOOK_BACKEND_EXCHANGE (backend);
 	EBookBackendExchangePrivate *bepriv = be->priv;
-	ExchangeAccount *account;
+	ExchangeAccount *account = NULL;
 
 	bepriv->mode = mode;
 	/* if (e_book_backend_is_loaded (backend)) { */
@@ -2863,7 +2867,7 @@ e_book_backend_exchange_set_mode (EBookBackend *backend,
 		e_book_backend_set_is_writable (backend, bepriv->is_writable);
 		e_book_backend_notify_writable (backend, bepriv->is_writable);
 		e_book_backend_notify_connection_status (backend, TRUE);
-		account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		account = exchange_share_config_listener_get_account_for_uri (NULL, bepriv->exchange_uri);
 		if (!exchange_account_get_context (account))
 			e_book_backend_notify_auth_required (backend);
 	}
@@ -2882,6 +2886,8 @@ e_book_backend_exchange_new (void)
 {
 	EBookBackendExchange *backend;
 
+	exchange_share_config_listener_get_account_for_uri (NULL, NULL);
+
 	backend = g_object_new (e_book_backend_exchange_get_type (), NULL);
 
 	if (! e_book_backend_exchange_construct (backend)) {
diff --git a/addressbook/e-book-backend-gal.c b/addressbook/e-book-backend-gal.c
index 0371a99..03ac4d3 100644
--- a/addressbook/e-book-backend-gal.c
+++ b/addressbook/e-book-backend-gal.c
@@ -35,7 +35,6 @@
 #include <e2k-utils.h>
 #include <e2k-global-catalog-ldap.h>
 #include <exchange-account.h>
-#include "exchange-component.h"
 
 #define d(x)
 
@@ -50,6 +49,7 @@
 #include <libedata-book/e-data-book.h>
 #include <libedata-book/e-data-book-view.h>
 #include "libedata-book/e-book-backend-summary.h"
+#include "tools/exchange-share-config-listener.h"
 #include "e-book-backend-gal.h"
 #include <libical/ical.h>
 
@@ -271,7 +271,7 @@ gal_connect (EBookBackendGAL *bl)
 	blpriv->gc = NULL;
 	blpriv->connected = FALSE;
 
-	blpriv->account = exchange_component_get_account_for_uri (global_exchange_component, blpriv->gal_uri);
+	blpriv->account = exchange_share_config_listener_get_account_for_uri (NULL, blpriv->gal_uri);
 	if (!blpriv->account)
 		return GNOME_Evolution_Addressbook_RepositoryOffline;
 	blpriv->gc = exchange_account_get_global_catalog (blpriv->account);
@@ -1711,7 +1711,7 @@ ldap_search_dtor (LDAPOp *op)
 	d(printf ("ldap_search_dtor: Setting null inplace of %p in view %p\n", op, search_op->view));
 	g_object_set_data (G_OBJECT (search_op->view), "EBookBackendGAL.BookView::search_op", NULL);
 
-	bonobo_object_unref (search_op->view);
+	e_data_book_view_unref (search_op->view);
 
 	if (!search_op->aborted)
 		g_free (search_op);
@@ -1923,7 +1923,7 @@ start_book_view (EBookBackend  *backend,
 				op->view = view;
 				op->aborted = FALSE;
 
-				bonobo_object_ref (view);
+				e_data_book_view_ref (view);
 
 				ldap_op_add ((LDAPOp*)op, E_BOOK_BACKEND (bl), NULL, view,
 					     0, search_msgid,
@@ -2325,7 +2325,7 @@ authenticate_user (EBookBackend *backend,
 	EBookBackendGAL *be = E_BOOK_BACKEND_GAL (backend);
 	EBookBackendGALPrivate *bepriv = be->priv;
 	ExchangeAccountResult result;
-	ExchangeAccount *account;
+	ExchangeAccount *account = NULL;
 	GNOME_Evolution_Addressbook_CallStatus res;
 	GConfClient *gc = gconf_client_get_default();
 	gint interval = gconf_client_get_int (gc, "/apps/evolution/addressbook/gal_cache_interval", NULL);
@@ -2348,7 +2348,7 @@ authenticate_user (EBookBackend *backend,
 
 	case GNOME_Evolution_Addressbook_MODE_REMOTE:
 
-		account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		account = exchange_share_config_listener_get_account_for_uri (NULL, bepriv->gal_uri);
 		/* FIXME : Check for failures */
 		if (!exchange_account_get_context (account)) {
 			exchange_account_set_online (account);
diff --git a/addressbook/e-book-backend-gal.h b/addressbook/e-book-backend-gal.h
index 43ad2f3..e074afe 100644
--- a/addressbook/e-book-backend-gal.h
+++ b/addressbook/e-book-backend-gal.h
@@ -5,7 +5,6 @@
 #define __E_BOOK_BACKEND_GAL_H__
 
 #include "libedata-book/e-book-backend.h"
-#include "exchange-component.h"
 
 #ifdef SUNLDAP
 /*   copy from openldap ldap.h   */
diff --git a/autogen.sh b/autogen.sh
index 1ba8eb6..dbbfd8b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -9,14 +9,14 @@ REQUIRED_AUTOMAKE_VERSION=1.6
 
 (test -f $srcdir/configure.ac \
   && test -f $srcdir/ChangeLog \
-  && test -d $srcdir/storage) || {
-    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
-    echo " top-level $PKG_NAME directory"
+  && test -d $srcdir/camel) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" >&2
+    echo " top-level $PKG_NAME directory" >&2
     exit 1
 }
 
 which gnome-autogen.sh || {
-    echo "You need to install gnome-common from the GNOME CVS"
+    echo "You need to install gnome-common from the GNOME git" >&2
     exit 1
 }
 USE_GNOME2_MACROS=1 . gnome-autogen.sh
diff --git a/calendar/Makefile.am b/calendar/Makefile.am
index 270cf09..2664176 100644
--- a/calendar/Makefile.am
+++ b/calendar/Makefile.am
@@ -1,6 +1,5 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir) \
-	-I$(top_srcdir)/storage \
 	$(CALENDAR_CFLAGS) \
 	$(LIBEXCHANGE_CFLAGS) \
 	$(LDAP_CFLAGS) \
@@ -26,4 +25,10 @@ libecalbackendexchange_la_SOURCES = \
 libecalbackendexchange_la_LDFLAGS = \
 	-module -avoid-version $(NO_UNDEFINED)
 
+libecalbackendexchange_la_LIBADD =  				\
+	$(top_builddir)/tools/libevolution-exchange-shared.la	\
+	$(CALENDAR_LIBS)					\
+	$(LIBEXCHANGE_LIBS)					\
+	$(LDAP_LIBS)
+
 -include $(top_srcdir)/git.mk
diff --git a/calendar/e-cal-backend-exchange-factory.c b/calendar/e-cal-backend-exchange-factory.c
index 62c0de5..6545f41 100644
--- a/calendar/e-cal-backend-exchange-factory.c
+++ b/calendar/e-cal-backend-exchange-factory.c
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <libebackend/e-data-server-module.h>
+#include <camel/camel-object.h>
 #include "e-cal-backend-exchange-factory.h"
 #include "e-cal-backend-exchange-calendar.h"
 #include "e-cal-backend-exchange-tasks.h"
@@ -98,7 +99,7 @@ e_cal_backend_exchange_events_factory_register_type (GTypeModule *type_module)
 		(GClassInitFunc) events_backend_exchange_factory_class_init,
 		(GClassFinalizeFunc) NULL,
 		NULL,  /* class_data */
-		sizeof (ECalBackendExchangeFactory),
+		sizeof (ECalBackend),
 		0,     /* n_preallocs */
 		(GInstanceInitFunc) NULL,
 		NULL   /* value_table */
@@ -125,7 +126,7 @@ e_cal_backend_exchange_todos_factory_register_type (GTypeModule *type_module)
 		(GClassInitFunc)  todos_backend_exchange_factory_class_init,
 		(GClassFinalizeFunc) NULL,
 		NULL,  /* class_data */
-		sizeof (ECalBackendExchangeFactory),
+		sizeof (ECalBackend),
 		0,     /* n_preallocs */
 		(GInstanceInitFunc) NULL,
 		NULL   /* value_table */
@@ -139,6 +140,10 @@ e_cal_backend_exchange_todos_factory_register_type (GTypeModule *type_module)
 void
 eds_module_initialize (GTypeModule *type_module)
 {
+	/* to have a camel type initialized properly */
+	camel_type_init ();
+	camel_object_get_type ();
+
 	e_cal_backend_exchange_events_factory_register_type (type_module);
 	e_cal_backend_exchange_todos_factory_register_type (type_module);
 }
diff --git a/calendar/e-cal-backend-exchange.c b/calendar/e-cal-backend-exchange.c
index 031ded6..aae4257 100644
--- a/calendar/e-cal-backend-exchange.c
+++ b/calendar/e-cal-backend-exchange.c
@@ -51,9 +51,10 @@
 #include <exchange-account.h>
 #include <exchange-hierarchy.h>
 
-#include "exchange-component.h"
 #include <e2k-utils.h>
 
+#include "tools/exchange-share-config-listener.h"
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
@@ -375,7 +376,7 @@ open_calendar (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
 			return GNOME_Evolution_Calendar_RepositoryOffline;
 		}
 
-		cbex->account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		cbex->account = exchange_share_config_listener_get_account_for_uri (NULL, uristr);
 
 		if (cbex->account) {
 			exchange_account_set_offline (cbex->account);
@@ -408,9 +409,7 @@ open_calendar (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
 	/* Make sure we have an open connection */
 	/* This steals the ExchangeAccount from ExchangeComponent */
 	if (!cbex->account) {
-		cbex->account = exchange_component_get_account_for_uri (global_exchange_component, uristr);
-		if (!cbex->account)
-			cbex->account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+		cbex->account = exchange_share_config_listener_get_account_for_uri (NULL, uristr);
 	}
 
 	if (!cbex->account) {
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 78a82ea..1b8b629 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,18 +31,18 @@ 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 359990c..c45243a 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 */
@@ -173,18 +174,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");
 	}
 
@@ -195,7 +189,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);
@@ -213,10 +206,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));
 }
@@ -235,14 +225,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) {
@@ -400,12 +389,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);
@@ -539,7 +523,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;
@@ -580,16 +563,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;
@@ -599,12 +578,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);
@@ -613,7 +592,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);
 		}
 	}
@@ -667,25 +646,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)
@@ -760,7 +734,7 @@ camel_exchange_folder_add_message (CamelExchangeFolder *exch,
 	camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream);
 	camel_object_unref (CAMEL_OBJECT (stream));
 
-	info = camel_folder_summary_info_new_from_message (folder->summary, msg);
+	info = camel_folder_summary_info_new_from_message (folder->summary, msg, NULL);
 	einfo = (CamelExchangeMessageInfo *)info;
 
 	if (einfo->thread_index) {
@@ -978,19 +952,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;
@@ -1064,10 +1034,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 ();
@@ -1089,17 +1057,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);
@@ -1108,23 +1068,21 @@ 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_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..af11fd0 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;
 }
 
@@ -285,7 +280,7 @@ exchange_entry_play_append (CamelOfflineJournal *journal, CamelExchangeJournalEn
 		return -1;
 	}
 
-	real = camel_folder_summary_info_new_from_message (folder->summary, message);
+	real = camel_folder_summary_info_new_from_message (folder->summary, message, NULL);
 	camel_object_unref (message);
 
 	if (uid != NULL && real) {
@@ -351,7 +346,7 @@ exchange_entry_play_transfer (CamelOfflineJournal *journal, CamelExchangeJournal
 		camel_exception_init (&lex);
 		camel_folder_transfer_messages_to (src, uids, folder, &xuids, entry->delete_original, &lex);
 		if (!camel_exception_is_set (&lex)) {
-			real = camel_folder_summary_info_new_from_message (folder->summary, message);
+			real = camel_folder_summary_info_new_from_message (folder->summary, message, NULL);
 			camel_object_unref (message);
 			real->uid = camel_pstring_strdup ((gchar *)xuids->pdata[0]);
 			/* Transfer flags */
@@ -457,7 +452,7 @@ update_cache (CamelExchangeJournal *exchange_journal, CamelMimeMessage *message,
 
 	camel_object_unref (cache);
 
-	info = camel_folder_summary_info_new_from_message (folder->summary, message);
+	info = camel_folder_summary_info_new_from_message (folder->summary, message, NULL);
 	info->uid = camel_pstring_strdup (uid);
 
 	exchange_message_info_dup_to ((CamelMessageInfoBase *) info, (CamelMessageInfoBase *) mi);
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 a6bc9b8..6d53f9c 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,57 +346,21 @@ 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;
 	}
@@ -412,8 +368,6 @@ exchange_connect (CamelService *service, CamelException *ex)
 	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_INBOX)
 		info->flags |= CAMEL_FOLDER_TYPE_INBOX;
 
-	if (flags & CAMEL_STUB_FOLDER_TYPE_TRASH)
+	if (flags & CAMEL_FOLDER_TYPE_TRASH)
 		info->flags |= CAMEL_FOLDER_TYPE_TRASH;
 
-	if (flags & CAMEL_STUB_FOLDER_TYPE_SENT)
+	if (flags & 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;
@@ -732,25 +657,14 @@ exchange_get_folder_info (CamelStore *store, const gchar *top, guint32 flags, Ca
 
 	RETURN_VAL_IF_NOT_CONNECTED (exch, ex, 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) {
@@ -771,6 +685,7 @@ exchange_get_folder_info (CamelStore *store, const gchar *top, guint32 flags, Ca
 			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);
@@ -798,19 +713,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;
 }
 
@@ -825,9 +736,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
@@ -848,15 +757,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;
 	}
 
@@ -878,6 +779,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);
@@ -905,291 +807,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..8d7a15f 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;
@@ -568,7 +552,7 @@ camel_exchange_summary_add_offline (CamelFolderSummary *summary,
 	const CamelTag *tag;
 
 	/* Create summary entry */
-	mi = (CamelMessageInfoBase *)camel_folder_summary_info_new_from_message (summary, message);
+	mi = (CamelMessageInfoBase *)camel_folder_summary_info_new_from_message (summary, message, NULL);
 
 	/* Copy flags 'n' tags */
 	mi->flags = camel_message_info_flags(info);
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/mail/mail-stub-exchange.c b/camel/camel-exchange-utils.c
similarity index 54%
rename from mail/mail-stub-exchange.c
rename to camel/camel-exchange-utils.c
index 6a5906a..e8b5253 100644
--- a/mail/mail-stub-exchange.c
+++ b/camel/camel-exchange-utils.c
@@ -17,60 +17,72 @@
  * Boston, MA 02111-1307, USA.
  */
 
-/* mail-stub-exchange.c: an Exchange implementation of MailStub */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "mail-stub-exchange.h"
-#include "mail-utils.h"
-
 #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 "camel-stub-constants.h"
 #include <e2k-propnames.h>
 #include <e2k-restriction.h>
 #include <e2k-uri.h>
 #include <e2k-utils.h>
-#include "exchange-component.h" // for using global_exchange_component
-#include "exchange-config-listener.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)
 
-#define PARENT_TYPE MAIL_TYPE_STUB
-static MailStubClass *parent_class = NULL;
+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;
 
-/* FIXME : Have this as part of the appropriate class in 2.5 */
-/* static gulong offline_listener_handler_id; */
+	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;
-} MailStubExchangeMessage;
+} ExchangeMessage;
 
 typedef enum {
-	MAIL_STUB_EXCHANGE_FOLDER_REAL,
-	MAIL_STUB_EXCHANGE_FOLDER_POST,
-	MAIL_STUB_EXCHANGE_FOLDER_NOTES,
-	MAIL_STUB_EXCHANGE_FOLDER_OTHER
-} MailStubExchangeFolderType;
+	EXCHANGE_FOLDER_REAL,
+	EXCHANGE_FOLDER_POST,
+	EXCHANGE_FOLDER_NOTES,
+	EXCHANGE_FOLDER_OTHER
+} ExchangeFolderType;
 
 typedef struct {
-	MailStubExchange *mse;
+	ExchangeData *ed;
 
 	EFolder *folder;
 	const gchar *name;
-	MailStubExchangeFolderType type;
+	ExchangeFolderType type;
 	guint32 access;
 
 	GPtrArray *messages;
@@ -85,227 +97,160 @@ typedef struct {
 
 	time_t last_activity;
 	guint sync_deletion_timeout;
-} MailStubExchangeFolder;
-
-static void dispose (GObject *);
-
-static void stub_connect (MailStub *stub, gchar *pwd);
-static void get_folder (MailStub *stub, const gchar *name, gboolean create,
-			GPtrArray *uids, GByteArray *flags, GPtrArray *hrefs, guint32 high_article_num);
-static void get_trash_name (MailStub *stub);
-static void sync_folder (MailStub *stub, const gchar *folder_name);
-static void refresh_folder (MailStub *stub, const gchar *folder_name);
-static void sync_count (MailStub *stub, const gchar *folder_name);
-static void refresh_folder_internal (MailStub *stub, MailStubExchangeFolder *mfld,
-				     gboolean background);
-static gboolean sync_deletions (MailStubExchange *mse, MailStubExchangeFolder *mfld);
-static void expunge_uids (MailStub *stub, const gchar *folder_name, GPtrArray *uids);
-static void append_message (MailStub *stub, const gchar *folder_name, guint32 flags,
-			    const gchar *subject, const gchar *data, gint length);
-static void set_message_flags (MailStub *, const gchar *folder_name,
-			       const gchar *uid, guint32 flags, guint32 mask);
-static void set_message_tag (MailStub *, const gchar *folder_name,
-			     const gchar *uid, const gchar *name, const gchar *value);
-static void get_message (MailStub *stub, const gchar *folder_name, const gchar *uid);
-static void search (MailStub *stub, const gchar *folder_name, const gchar *text);
-static void transfer_messages (MailStub *stub, const gchar *source_name,
-			       const gchar *dest_name, GPtrArray *uids,
-			       gboolean delete_originals);
-static void get_folder_info (MailStub *stub, const gchar *top,
-			     guint32 store_flags);
-static void send_message (MailStub *stub, const gchar *from,
-			  GPtrArray *recipients,
-			  const gchar *data, gint length);
-static void create_folder (MailStub *, const gchar *parent_name,
-			   const gchar *folder_name);
-static void delete_folder (MailStub *, const gchar *folder_name);
-static void rename_folder (MailStub *, const gchar *old_name,
-			   const gchar *new_name);
-static void subscribe_folder (MailStub *, const gchar *folder_name);
-static void unsubscribe_folder (MailStub *, const gchar *folder_name);
-static void is_subscribed_folder (MailStub *, const gchar *folder_name);
-
-static gboolean process_flags (gpointer user_data);
-
-static void storage_folder_changed (EFolder *folder, gpointer user_data);
-
-/* static void linestatus_listener (ExchangeComponent *component,
-						    gint linestatus,
-						    gpointer data); */
-static void folder_update_linestatus (gpointer key, gpointer value, gpointer data);
-static void free_folder (gpointer value);
-static gboolean get_folder_online (MailStubExchangeFolder *mfld, gboolean background);
-static void  get_folder_info_data (MailStub *stub, const gchar *top, guint32 store_flags,
-				   GPtrArray **names, GPtrArray **uris,
-				   GArray **unread, GArray **flags);
+} ExchangeFolder;
 
-static GStaticRecMutex g_changed_msgs_mutex = G_STATIC_REC_MUTEX_INIT;
-
-static void
-class_init (GObjectClass *object_class)
-{
-	MailStubClass *stub_class = MAIL_STUB_CLASS (object_class);
-
-	parent_class = g_type_class_ref (PARENT_TYPE);
-
-	/* virtual method override */
-	object_class->dispose = dispose;
-
-	stub_class->connect = stub_connect;
-	stub_class->get_folder = get_folder;
-	stub_class->get_trash_name = get_trash_name;
-	stub_class->sync_folder = sync_folder;
-	stub_class->refresh_folder = refresh_folder;
-	stub_class->sync_count = sync_count;
-	stub_class->expunge_uids = expunge_uids;
-	stub_class->append_message = append_message;
-	stub_class->set_message_flags = set_message_flags;
-	stub_class->set_message_tag = set_message_tag;
-	stub_class->get_message = get_message;
-	stub_class->search = search;
-	stub_class->transfer_messages = transfer_messages;
-	stub_class->get_folder_info = get_folder_info;
-	stub_class->send_message = send_message;
-	stub_class->create_folder = create_folder;
-	stub_class->delete_folder = delete_folder;
-	stub_class->rename_folder = rename_folder;
-	stub_class->subscribe_folder = subscribe_folder;
-	stub_class->unsubscribe_folder = unsubscribe_folder;
-	stub_class->is_subscribed_folder = is_subscribed_folder;
-}
+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 void
-init (GObject *object)
+static gboolean
+is_same_ed (CamelExchangeStore *estore, ExchangeAccount *eaccount, CamelService *service)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (object);
+	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);
 
-	mse->folders_by_name = g_hash_table_new_full (g_str_hash, g_str_equal,
-						      NULL, free_folder);
-}
+	if (CAMEL_IS_EXCHANGE_STORE (service) && estore && estore == CAMEL_EXCHANGE_STORE (service))
+		return TRUE;
 
-static void
-free_message (MailStubExchangeMessage *mmsg)
-{
-	g_datalist_clear (&mmsg->tag_updates);
-	g_free (mmsg->uid);
-	g_free (mmsg->href);
-	g_free (mmsg);
-}
+	if (service->url) {
+		if (estore && camel_url_equal (CAMEL_SERVICE (estore)->url, service->url))
+			return TRUE;
 
-static void
-free_folder (gpointer value)
-{
-	MailStubExchangeFolder *mfld = value;
-	gint i;
+		if (eaccount) {
+			EAccount *account = exchange_account_fetch (eaccount);
 
-	d(g_print ("%s:%s:%d: freeing mfld: name=[%s]\n", __FILE__, __PRETTY_FUNCTION__, __LINE__,
-		   mfld->name));
+			/* 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);
 
-	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;
+				if (url) {
+					CamelProvider *provider = camel_service_get_provider (service);
 
-	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);
+					if ((provider && provider->url_equal && provider->url_equal (url, service->url))
+					    || camel_url_equal (url, service->url)) {
+						camel_url_free (url);
+						return TRUE;
+					}
 
-	g_ptr_array_free (mfld->changed_messages, TRUE);
-	if (mfld->flag_timeout) {
-		g_warning ("unreffing mse with unsynced flags");
-		g_source_remove (mfld->flag_timeout);
+					camel_url_free (url);
+				}
+			}
+		}
 	}
-	if (mfld->sync_deletion_timeout)
-		g_source_remove (mfld->sync_deletion_timeout);
-	g_free (mfld);
+
+	return FALSE;
 }
 
-static void
-dispose (GObject *object)
+static void free_folder (gpointer value);
+
+static ExchangeData *
+get_data_for_service (CamelService *service)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (object);
+	static GSList *edies = NULL;
+	G_LOCK_DEFINE_STATIC (edies);
 
-	if (mse->folders_by_name) {
-		g_hash_table_destroy (mse->folders_by_name);
-		mse->folders_by_name = NULL;
-	}
+	GSList *p, *accounts;
+	ExchangeData *res = NULL;
 
-	if (mse->ctx) {
-		g_object_unref (mse->ctx);
-		mse->ctx = NULL;
-	}
+	g_return_val_if_fail (service != NULL, NULL);
+	g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
 
-	if (mse->new_folder_id != 0) {
-		g_signal_handler_disconnect (mse->account, mse->new_folder_id);
-		mse->new_folder_id = 0;
-		g_signal_handler_disconnect (mse->account, mse->removed_folder_id);
-		mse->removed_folder_id = 0;
+	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;
+		}
 	}
 
-/*	if (g_signal_handler_is_connected (G_OBJECT (global_exchange_component),
-					   offline_listener_handler_id)) {
-		g_signal_handler_disconnect (G_OBJECT (global_exchange_component),
-					      offline_listener_handler_id);
-		offline_listener_handler_id = 0;
+	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_OBJECT_CLASS (parent_class)->dispose (object);
+
+	g_slist_free (accounts);
+
+	G_UNLOCK (edies);
+
+	return res;
 }
 
-E2K_MAKE_TYPE (mail_stub_exchange, MailStubExchange, class_init, init, PARENT_TYPE)
+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 MailStubExchangeFolder *
-folder_from_name (MailStubExchange *mse, const gchar *folder_name,
-		  guint32 perms, gboolean background)
+static void
+set_exception (CamelException *ex, const gchar *err)
 {
-	MailStubExchangeFolder *mfld;
+	g_return_if_fail (err != NULL);
 
-	mfld = g_hash_table_lookup (mse->folders_by_name, folder_name);
-	if (!mfld) {
-		if (!background)
-			mail_stub_return_error (MAIL_STUB (mse), _("No such folder"));
-		return NULL;
-	}
+	if (ex && !camel_exception_is_set (ex))
+		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, err);
+}
 
-	/* 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 (mse, mfld);
-	}
+static CamelFolder *
+get_camel_folder (ExchangeFolder *mfld)
+{
+	CamelFolder *folder;
 
-	if ((perms == MAPI_ACCESS_MODIFY || perms == MAPI_ACCESS_DELETE) &&
-	    !(mfld->access & perms)) {
-		/* try with MAPI_ACCESS_CREATE_CONTENTS */
-		perms = MAPI_ACCESS_CREATE_CONTENTS;
-	}
+	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);
 
-	if (perms && !(mfld->access & perms)) {
-		if (!background)
-			mail_stub_return_error (MAIL_STUB (mse), _("Permission denied"));
-		return 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);
 
-	mfld->last_activity = time (NULL);
-	return mfld;
+	return folder;
 }
 
 static void
-folder_changed (MailStubExchangeFolder *mfld)
+folder_changed (ExchangeFolder *mfld)
 {
 	e_folder_set_unread_count (mfld->folder, mfld->unread_count);
 }
 
 static gint
-find_message_index (MailStubExchangeFolder *mfld, gint seq)
+find_message_index (ExchangeFolder *mfld, gint seq)
 {
-	MailStubExchangeMessage *mmsg;
+	ExchangeMessage *mmsg;
 	gint low, high, mid;
 
 	low = 0;
@@ -325,24 +270,24 @@ find_message_index (MailStubExchangeFolder *mfld, gint seq)
 	return -1;
 }
 
-static inline MailStubExchangeMessage *
-find_message (MailStubExchangeFolder *mfld, const gchar *uid)
+static inline ExchangeMessage *
+find_message (ExchangeFolder *mfld, const gchar *uid)
 {
 	return g_hash_table_lookup (mfld->messages_by_uid, uid);
 }
 
-static inline MailStubExchangeMessage *
-find_message_by_href (MailStubExchangeFolder *mfld, const gchar *href)
+static inline ExchangeMessage *
+find_message_by_href (ExchangeFolder *mfld, const gchar *href)
 {
 	return g_hash_table_lookup (mfld->messages_by_href, href);
 }
 
-static MailStubExchangeMessage *
+static ExchangeMessage *
 new_message (const gchar *uid, const gchar *uri, guint32 seq, guint32 flags)
 {
-	MailStubExchangeMessage *mmsg;
+	ExchangeMessage *mmsg;
 
-	mmsg = g_new0 (MailStubExchangeMessage, 1);
+	mmsg = g_new0 (ExchangeMessage, 1);
 	mmsg->uid = g_strdup (uid);
 	mmsg->href = g_strdup (uri);
 	mmsg->seq = seq;
@@ -352,27 +297,28 @@ new_message (const gchar *uid, const gchar *uri, guint32 seq, guint32 flags)
 }
 
 static void
-message_remove_at_index (MailStub *stub, MailStubExchangeFolder *mfld, gint index)
+message_remove_at_index (ExchangeFolder *mfld, CamelFolder *folder, gint index)
 {
-	MailStubExchangeMessage *mmsg;
+	ExchangeMessage *mmsg;
+	CamelMessageInfo *info;
 
 	mmsg = mfld->messages->pdata[index];
 	d(printf("Deleting mmsg %p\n", mmsg));
-	g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+	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 & MAIL_STUB_MESSAGE_SEEN)) {
+	if (!(mmsg->flags & CAMEL_MESSAGE_SEEN)) {
 		mfld->unread_count--;
 		folder_changed (mfld);
 	}
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 
 	if (mmsg->change_mask || mmsg->tag_updates) {
 		gint i;
 
-		g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+		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) {
@@ -380,15 +326,15 @@ message_remove_at_index (MailStub *stub, MailStubExchangeFolder *mfld, gint inde
 				break;
 			}
 		}
-		g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 
 		g_datalist_clear (&mmsg->tag_updates);
 	}
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_REMOVED_MESSAGE,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_STRING, mmsg->uid,
-			       CAMEL_STUB_ARG_END);
+	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);
@@ -396,56 +342,22 @@ message_remove_at_index (MailStub *stub, MailStubExchangeFolder *mfld, gint inde
 }
 
 static void
-message_removed (MailStub *stub, MailStubExchangeFolder *mfld, const gchar *href)
+message_removed (ExchangeFolder *mfld, CamelFolder *folder, const gchar *href)
 {
-	MailStubExchangeMessage *mmsg;
+	ExchangeMessage *mmsg;
 	guint index;
 
-	g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+	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 (&g_changed_msgs_mutex);
+		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 (stub, mfld, index);
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-}
-
-static void
-return_tag (MailStubExchangeFolder *mfld, const gchar *uid,
-	    const gchar *name, const gchar *value)
-{
-	mail_stub_return_data (MAIL_STUB (mfld->mse),
-			       CAMEL_STUB_RETVAL_CHANGED_TAG,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_STRING, uid,
-			       CAMEL_STUB_ARG_STRING, name,
-			       CAMEL_STUB_ARG_STRING, value,
-			       CAMEL_STUB_ARG_END);
-}
-
-static void
-change_flags (MailStubExchangeFolder *mfld, MailStubExchangeMessage *mmsg,
-	      guint32 new_flags)
-{
-	if ((mmsg->flags ^ new_flags) & MAIL_STUB_MESSAGE_SEEN) {
-		if (mmsg->flags & MAIL_STUB_MESSAGE_SEEN)
-			mfld->unread_count++;
-		else
-			mfld->unread_count--;
-		folder_changed (mfld);
-	}
-	mmsg->flags = new_flags;
-
-	mail_stub_return_data (MAIL_STUB (mfld->mse),
-			       CAMEL_STUB_RETVAL_CHANGED_FLAGS,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_STRING, mmsg->uid,
-			       CAMEL_STUB_ARG_UINT32, mmsg->flags,
-			       CAMEL_STUB_ARG_END);
+	message_remove_at_index (mfld, folder, index);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 }
 
 static const gchar *
@@ -463,135 +375,481 @@ uidstrip (const gchar *repl_uid)
 		return repl_uid + 36;
 }
 
-#define FIVE_SECONDS (5)
-#define  ONE_MINUTE  (60)
-#define FIVE_MINUTES (60*5)
+struct refresh_message {
+	gchar *uid, *href, *headers, *fff, *reply_by, *completed;
+	guint32 flags, size, article_num;
+};
 
-static gboolean
-timeout_sync_deletions (gpointer user_data)
+static gint
+refresh_message_compar (gconstpointer a, gconstpointer b)
 {
-	MailStubExchangeFolder *mfld = user_data;
+	const struct refresh_message *rma = a, *rmb = b;
 
-	sync_deletions (mfld->mse, mfld);
-	return FALSE;
+	return strcmp (rma->uid, rmb->uid);
 }
 
 static void
-notify_cb (E2kContext *ctx, const gchar *uri,
-	   E2kContextChangeType type, gpointer user_data)
+change_flags (ExchangeFolder *mfld, CamelFolder *folder, ExchangeMessage *mmsg, guint32 new_flags)
 {
-	MailStubExchangeFolder *mfld = user_data;
-	time_t now;
+	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 (type == E2K_CONTEXT_OBJECT_ADDED)
-		refresh_folder_internal (MAIL_STUB (mfld->mse), mfld, TRUE);
-	else {
-		now = time (NULL);
+	if (folder)
+		camel_exchange_folder_update_message_flags (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, mmsg->flags);
+}
 
-		/* If the user did something in Evolution in the
-		 * last 5 seconds, assume that this notification is
-		 * a result of that and ignore it.
+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.
 		 */
-		if (now < mfld->last_activity + FIVE_SECONDS)
+		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;
+		}
 
-		/* 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->deleted_count == 0) {
+			mfld->deleted_count = deleted_count;
+			g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
+			return;
+		}
+	}
 
-		if (mfld->sync_deletion_timeout) {
-			g_source_remove (mfld->sync_deletion_timeout);
-			mfld->sync_deletion_timeout = 0;
+	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;
 		}
 
-		if (now < mfld->last_activity + ONE_MINUTE)
-			sync_deletions (mfld->mse, 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);
+		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)
 {
-	MailStubExchangeFolder *mfld = user_data;
+	ExchangeFolder *mfld = user_data;
 
 	if (e_folder_get_unread_count (folder) > mfld->unread_count)
-		refresh_folder_internal (MAIL_STUB (mfld->mse), mfld, TRUE);
+		refresh_folder_internal (mfld, NULL);
 }
 
 static void
-got_folder_error (MailStubExchangeFolder *mfld, const gchar *error)
+free_message (ExchangeMessage *mmsg)
 {
-	mail_stub_return_error (MAIL_STUB (mfld->mse), error);
-	free_folder (mfld);
+	g_datalist_clear (&mmsg->tag_updates);
+	g_free (mmsg->uid);
+	g_free (mmsg->href);
+	g_free (mmsg);
 }
 
-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
-};
-static const gint n_open_folder_sync_props = sizeof (open_folder_sync_props) / sizeof (open_folder_sync_props[0]);
+static void
+free_folder (gpointer value)
+{
+	ExchangeFolder *mfld = value;
+	gint i;
 
-static const gchar *open_folder_props[] = {
-	PR_ACCESS,
-	PR_DELETED_COUNT_TOTAL
-};
-static const gint n_open_folder_props = sizeof (open_folder_props) / sizeof (open_folder_props[0]);
+	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
-mse_get_folder_online_sync_updates (gpointer key, gpointer value,
-				    gpointer user_data)
+mfld_get_folder_online_sync_updates (gpointer key, gpointer value, gpointer user_data)
 {
 	guint index, seq, i;
-	MailStubExchangeFolder *mfld = (MailStubExchangeFolder *)user_data;
-	/*MailStub *stub = MAIL_STUB (mfld->mse);*/
-	MailStubExchangeMessage *mmsg = NULL;
+	ExchangeFolder *mfld = (ExchangeFolder *) user_data;
+	ExchangeMessage *mmsg = NULL;
 
 	index = GPOINTER_TO_UINT (key);
 	seq = GPOINTER_TO_UINT (value);
 
-	g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+	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 (&g_changed_msgs_mutex);
+		g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 		return;
 	}
 
@@ -604,7 +862,7 @@ mse_get_folder_online_sync_updates (gpointer key, gpointer value,
 		}
 		seq = i;
 	}
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 
 	/* FIXME FIXME FIXME: Some miscalculation happens here,though,
 	not a serious one
@@ -613,11 +871,23 @@ mse_get_folder_online_sync_updates (gpointer key, gpointer value,
 	/*message_remove_at_index (stub, mfld, seq);*/
 
 }
+
 static gboolean
-get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
-{
-	MailStubExchangeMessage *mmsg, *mmsg_cpy;
-	MailStub *stub = MAIL_STUB (mfld->mse);
+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;
@@ -627,6 +897,7 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 	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;
@@ -637,14 +908,14 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 	/* 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 (&g_changed_msgs_mutex);
+	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 (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 
 	rn = e2k_restriction_andv (
 		e2k_restriction_prop_bool (E2K_PR_DAV_IS_COLLECTION,
@@ -655,11 +926,13 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 
 	iter = e_folder_exchange_search_start (mfld->folder, NULL,
 					       open_folder_sync_props,
-					       n_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))) {
@@ -706,7 +979,7 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 		if (article_num > high_article_num)
 			high_article_num = article_num;
 
-		g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+		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,
@@ -735,27 +1008,27 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 		}
 
 		if (mmsg->flags != camel_flags)
-			change_flags (mfld, mmsg, camel_flags);
+			change_flags (mfld, folder, mmsg, camel_flags);
 
-		g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
+		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)
-			return_tag (mfld, mmsg->uid, "follow-up", prop);
+		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)
-			return_tag (mfld, mmsg->uid, "due-by", prop);
+		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)
-			return_tag (mfld, mmsg->uid, "completed-on", prop);
+		if (prop && folder)
+			camel_exchange_folder_update_message_tag (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, "completed-on", prop);
 
 		m++;
 #if 0
-		if (!background) {
-			mail_stub_return_progress (stub, (m * 100) / total);
+		if (ex) {
+			camel_operation_progress (NULL, (m * 100) / total);
 		}
 #endif
 	}
@@ -778,17 +1051,15 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 
 		m++;
 #if 0
-		if (!background) {
-			mail_stub_return_progress (stub, (m * 100) / total);
+		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);
-		if (!background) {
-			got_folder_error (mfld, _("Could not open folder"));
-		}
+		got_folder_error (mfld, ex, _("Could not open folder"));
 		return FALSE;
 	}
 
@@ -812,17 +1083,14 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 		g_free (mmsg_cpy);
 	}
 
-	g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+	g_static_rec_mutex_lock (&mfld->ed->changed_msgs_mutex);
 	mfld->high_article_num = high_article_num;
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&mfld->ed->changed_msgs_mutex);
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FOLDER_SET_ARTICLE_NUM,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_UINT32, mfld->high_article_num,
-			       CAMEL_STUB_ARG_END);
+	if (folder)
+		camel_exchange_summary_set_article_num (folder->summary, mfld->high_article_num);
 
-	g_hash_table_foreach (rm_idx_uid, mse_get_folder_online_sync_updates,
-			      mfld);
+	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);
@@ -830,35 +1098,101 @@ get_folder_contents_online (MailStubExchangeFolder *mfld, gboolean background)
 	return TRUE;
 }
 
-struct _get_folder_thread_data {
-	MailStubExchangeFolder *mfld;
-	gboolean background;
-};
-
 static gpointer
 get_folder_contents_online_func (gpointer data)
 {
-	MailStubExchangeFolder* mfld;
-	gboolean background;
+	ExchangeFolder *mfld = data;
 
-	struct _get_folder_thread_data *gf_thread_data = (struct _get_folder_thread_data *)data;
-	if (!gf_thread_data)
+	if (!mfld)
 		return NULL;
 
-	mfld = gf_thread_data->mfld;
-	background = gf_thread_data->background;
+	get_folder_contents_online (mfld, NULL);
 
-	get_folder_contents_online (mfld, background);
+	return NULL;
+}
 
-	g_free (gf_thread_data);
+#define FIVE_SECONDS (5)
+#define  ONE_MINUTE  (60)
+#define FIVE_MINUTES (60*5)
 
-	return NULL;
+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 (MailStubExchangeFolder *mfld, gboolean background)
+get_folder_online (ExchangeFolder *mfld, CamelException *ex)
 {
-	MailStub *stub = MAIL_STUB (mfld->mse);
+	static const gchar *open_folder_props[] = {
+		PR_ACCESS,
+		PR_DELETED_COUNT_TOTAL
+	};
+
 	E2kHTTPStatus status;
 	E2kResult *results;
 	gint nresults = 0;
@@ -869,18 +1203,14 @@ get_folder_online (MailStubExchangeFolder *mfld, gboolean background)
 
 	status = e_folder_exchange_propfind (mfld->folder, NULL,
 					     open_folder_props,
-					     n_open_folder_props,
+					     G_N_ELEMENTS (open_folder_props),
 					     &results, &nresults);
 	if (status == E2K_HTTP_UNAUTHORIZED) {
-		if (!background) {
-			got_folder_error (mfld, _("Could not open folder: Permission denied"));
-		}
+		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);
-		if (!background) {
-			got_folder_error (mfld, _("Could not open folder"));
-		}
+		got_folder_error (mfld, ex, _("Could not open folder"));
 		return FALSE;
 	}
 
@@ -894,9 +1224,7 @@ get_folder_online (MailStubExchangeFolder *mfld, gboolean background)
 		mfld->access = ~0;
 
 	if (!(mfld->access & MAPI_ACCESS_READ)) {
-		if (!background) {
-			got_folder_error (mfld, _("Could not open folder: Permission denied"));
-		}
+		got_folder_error (mfld, ex, _("Could not open folder: Permission denied"));
 		if (nresults)
 			e2k_results_free (results, nresults);
 		return FALSE;
@@ -915,19 +1243,12 @@ get_folder_online (MailStubExchangeFolder *mfld, gboolean background)
 	   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, background))
+		if (!get_folder_contents_online (mfld, ex))
 			return FALSE;
 	} else {
-		struct _get_folder_thread_data *gf_thread_data = NULL;
-
-		gf_thread_data = g_new0 (struct _get_folder_thread_data, 1);
-		gf_thread_data->mfld = mfld;
-		gf_thread_data->background = background;
-
 		/* FIXME: Pass a GError and handle the error */
 		g_thread_create (get_folder_contents_online_func,
-				 gf_thread_data, FALSE,
-				 NULL);
+				 mfld, FALSE, NULL);
 	}
 
 	e_folder_exchange_subscribe (mfld->folder,
@@ -939,712 +1260,47 @@ get_folder_online (MailStubExchangeFolder *mfld, gboolean background)
 	e_folder_exchange_subscribe (mfld->folder,
 				     E2K_CONTEXT_OBJECT_MOVED, 30,
 				     notify_cb, mfld);
-	if (background) {
-		mail_stub_push_changes (stub);
-	}
 	if (nresults)
 		e2k_results_free (results, nresults);
-	return TRUE;
-}
-
-static void
-get_folder (MailStub *stub, const gchar *name, gboolean create,
-	    GPtrArray *uids, GByteArray *flags, GPtrArray *hrefs,
-	    guint32 high_article_num)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	MailStubExchangeMessage *mmsg;
-	EFolder *folder;
-	gchar *path;
-	const gchar *outlook_class;
-	guint32 camel_flags;
-	gint i, mode;
-	ExchangeHierarchy *hier;
-
-	path = g_strdup_printf ("/%s", name);
-	folder = exchange_account_get_folder (mse->account, path);
-	if (!folder && !create) {
-		mail_stub_return_error (stub, _("No such folder"));
-		g_free (path);
-		return;
-	} else if (!folder) {
-		ExchangeAccountFolderResult result;
-
-		result = exchange_account_create_folder (mse->account, path, "mail");
-		folder = exchange_account_get_folder (mse->account, path);
-		if (result != EXCHANGE_ACCOUNT_FOLDER_OK || !folder) {
-			mail_stub_return_error (stub, _("Could not create folder."));
-			g_free (path);
-			return;
-		}
-	}
-	g_free (path);
-
-	mfld = g_new0 (MailStubExchangeFolder, 1);
-	mfld->mse = MAIL_STUB_EXCHANGE (stub);
-	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 = MAIL_STUB_EXCHANGE_FOLDER_POST;
-	else {
-		outlook_class = e_folder_exchange_get_outlook_class (folder);
-		if (!outlook_class)
-			mfld->type = MAIL_STUB_EXCHANGE_FOLDER_OTHER;
-		else if (!g_ascii_strncasecmp (outlook_class, "IPF.Note", 8))
-			mfld->type = MAIL_STUB_EXCHANGE_FOLDER_REAL;
-		else if (!g_ascii_strncasecmp (outlook_class, "IPF.Post", 8))
-			mfld->type = MAIL_STUB_EXCHANGE_FOLDER_POST;
-		else if (!g_ascii_strncasecmp (outlook_class, "IPF.StickyNote", 14))
-			mfld->type = MAIL_STUB_EXCHANGE_FOLDER_NOTES;
-		else
-			mfld->type = MAIL_STUB_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 & MAIL_STUB_MESSAGE_SEEN))
-			mfld->unread_count++;
-	}
-
-	mfld->high_article_num = high_article_num;
-
-	exchange_component_is_offline (global_exchange_component, &mode);
-	if (mode == ONLINE_MODE) {
-		if (!get_folder_online (mfld, FALSE)) {
-			return;
-		}
-	}
-	g_signal_connect (mfld->folder, "changed",
-			  G_CALLBACK (storage_folder_changed), mfld);
-
-	g_hash_table_insert (mse->folders_by_name, (gchar *)mfld->name, mfld);
-	folder_changed (mfld);
-
-	camel_flags = 0;
-	if ((mfld->access & (MAPI_ACCESS_MODIFY | MAPI_ACCESS_CREATE_CONTENTS)) == 0)
-		camel_flags |= CAMEL_STUB_FOLDER_READONLY;
-	if (mse->account->filter_inbox && (mfld->folder == mse->inbox))
-		camel_flags |= CAMEL_STUB_FOLDER_FILTER;
-	if (mse->account->filter_junk) {
-		if ((mfld->folder != mse->deleted_items) &&
-		    ((mfld->folder == mse->inbox) ||
-		    !mse->account->filter_junk_inbox_only))
-			camel_flags |= CAMEL_STUB_FOLDER_FILTER_JUNK;
-	}
-	if (mfld->type == MAIL_STUB_EXCHANGE_FOLDER_POST)
-		camel_flags |= CAMEL_STUB_FOLDER_POST;
-
-	hier = e_folder_exchange_get_hierarchy (mfld->folder);
-
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_UINT32, camel_flags,
-			       CAMEL_STUB_ARG_STRING, hier->source_uri,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
-}
-
-static void
-get_trash_name (MailStub *stub)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-
-	if (!mse->deleted_items) {
-		mail_stub_return_error (stub, _("Could not open Deleted Items folder"));
-		return;
-	}
-
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_STRING, e_folder_exchange_get_path (mse->deleted_items) + 1,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
-}
-
-static void
-sync_folder (MailStub *stub, const gchar *folder_name)
-{
-	MailStubExchangeFolder *mfld;
-
-	mfld = folder_from_name (MAIL_STUB_EXCHANGE (stub), folder_name, 0, FALSE);
-	if (!mfld)
-		return;
-
-	while (mfld->flag_timeout)
-		process_flags (mfld);
-	while (mfld->pending_delete_ops)
-		g_main_context_iteration (NULL, TRUE);
-
-	mail_stub_return_ok (stub);
-}
-
-static const gchar *sync_deleted_props[] = {
-	PR_DELETED_COUNT_TOTAL,
-	E2K_PR_DAV_VISIBLE_COUNT
-};
-static const gint n_sync_deleted_props = sizeof (sync_deleted_props) / sizeof (sync_deleted_props[0]);
-
-static gboolean
-sync_deletions (MailStubExchange *mse, MailStubExchangeFolder *mfld)
-{
-	MailStub *stub = MAIL_STUB (mse);
-	E2kHTTPStatus status;
-	E2kResult *results;
-	gint nresults = 0;
-	const gchar *prop;
-	gint deleted_count = -1, visible_count = -1, mode;
-	E2kRestriction *rn;
-	E2kResultIter *iter;
-	E2kResult *result;
-	gint my_i, read;
-	MailStubExchangeMessage *mmsg;
-	gboolean changes = FALSE;
-	GHashTable *known_messages;
-
-	exchange_component_is_offline (global_exchange_component, &mode);
-	if (mode != ONLINE_MODE)
-		return FALSE;
-
-	status = e_folder_exchange_propfind (mfld->folder, NULL,
-					     sync_deleted_props,
-					     n_sync_deleted_props,
-					     &results, &nresults);
-
-	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || !nresults) {
-		g_warning ("got_sync_deleted_props: %d", status);
-		return FALSE;
-	}
-
-	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 (&g_changed_msgs_mutex);
-	if (visible_count >= mfld->messages->len) {
-		if (mfld->deleted_count == deleted_count) {
-			g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-			return FALSE;
-		}
-
-		if (mfld->deleted_count == 0) {
-			mfld->deleted_count = deleted_count;
-			g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-			return FALSE;
-		}
-	}
-
-	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);
-
-	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)) ? MAIL_STUB_MESSAGE_SEEN : 0;
-		if ((mmsg->flags & MAIL_STUB_MESSAGE_SEEN) != read) {
-			changes = TRUE;
-			change_flags (mfld, mmsg,
-				      mmsg->flags ^ MAIL_STUB_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 (stub, mfld, my_i);
-			changes = TRUE;
-		}
-	}
-
-	g_hash_table_destroy (known_messages);
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-
-	if (changes)
-		mail_stub_push_changes (stub);
-
-	return changes;
-}
-
-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 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 const gint n_mapi_message_props = sizeof (mapi_message_props) / sizeof (mapi_message_props[0]);
-
-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
-};
-static const gint num_new_message_props = sizeof (new_message_props) / sizeof (new_message_props[0]);
 
-static void
-refresh_folder_internal (MailStub *stub, MailStubExchangeFolder *mfld,
-			 gboolean background)
-{
-	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, mode;
-	gpointer key, value;
-	MailStubExchangeMessage *mmsg;
-
-	g_object_ref (stub);
-
-	exchange_component_is_offline (global_exchange_component, &mode);
-	if (mode == OFFLINE_MODE) {
-		if (background)
-			mail_stub_push_changes (stub);
-		else
-			mail_stub_return_ok (stub);
-
-		g_object_unref (stub); /* Is this needed ? */
-		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,
-					       num_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++;
-			mail_stub_return_progress (stub, (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);
-		if (!background)
-			mail_stub_return_error (stub, _("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,
-						  n_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++;
-		mail_stub_return_progress (stub, (got * 100) / total);
-	}
-	status = e2k_result_iter_free (iter);
-
-	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
-		g_warning ("got_new_mapi_messages: %d", status);
-		if (!background)
-			mail_stub_return_error (stub, _("Could not get new messages"));
-		goto done;
-	}
-
-	/*
-	 * STEP 3: Organize the data, update our records and Camel's
-	 */
-
- return_data:
-	mail_stub_return_progress (stub, 100);
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FREEZE_FOLDER,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_END);
-
-	g_static_rec_mutex_lock (&g_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, mmsg, rm.flags);
-		} else {
-			if (g_hash_table_lookup (mfld->messages_by_href, rm.href)) {
-				mfld->deleted_count++;
-				message_removed (stub, mfld, 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 & MAIL_STUB_MESSAGE_SEEN))
-				mfld->unread_count++;
-
-			mail_stub_return_data (stub, CAMEL_STUB_RETVAL_NEW_MESSAGE,
-					       CAMEL_STUB_ARG_FOLDER, mfld->name,
-					       CAMEL_STUB_ARG_STRING, rm.uid,
-					       CAMEL_STUB_ARG_UINT32, rm.flags,
-					       CAMEL_STUB_ARG_UINT32, rm.size,
-					       CAMEL_STUB_ARG_STRING, rm.headers,
-					       CAMEL_STUB_ARG_STRING, rm.href,
-					       CAMEL_STUB_ARG_END);
-		}
-
-		if (rm.article_num > mfld->high_article_num) {
-			mfld->high_article_num = rm.article_num;
-			mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FOLDER_SET_ARTICLE_NUM,
-					       CAMEL_STUB_ARG_FOLDER, mfld->name,
-					       CAMEL_STUB_ARG_UINT32, mfld->high_article_num,
-					       CAMEL_STUB_ARG_END);
-		}
-
-		if (rm.fff)
-			return_tag (mfld, rm.uid, "follow-up", rm.fff);
-		if (rm.reply_by)
-			return_tag (mfld, rm.uid, "due-by", rm.reply_by);
-		if (rm.completed)
-			return_tag (mfld, rm.uid, "completed-on", rm.completed);
-	}
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_THAW_FOLDER,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_END);
-
-	mfld->scanned = TRUE;
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-	folder_changed (mfld);
-
-	if (background)
-		mail_stub_push_changes (stub);
-	else
-		mail_stub_return_ok (stub);
-
- 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);
-
-	g_object_unref (stub);
+	return TRUE;
 }
 
-static void
-sync_count (MailStub *stub, const gchar *folder_name)
+static ExchangeFolder *
+folder_from_name (ExchangeData *ed, const gchar *folder_name, guint32 perms, CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	guint32 unread_count = 0, visible_count = 0;
+	ExchangeFolder *mfld;
 
-	mfld = folder_from_name (mse, folder_name, 0, FALSE);
+	mfld = g_hash_table_lookup (ed->folders_by_name, folder_name);
 	if (!mfld) {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-				       CAMEL_STUB_ARG_UINT32, unread_count,
-				       CAMEL_STUB_ARG_UINT32, visible_count,
-				       CAMEL_STUB_ARG_END);
-		mail_stub_return_ok (stub);
-		return;
-	}
-
-	unread_count = mfld->unread_count;
-	visible_count = mfld->messages->len;
-
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_UINT32, unread_count,
-			       CAMEL_STUB_ARG_UINT32, visible_count,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
-}
-
-static void
-refresh_folder (MailStub *stub, const gchar *folder_name)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-
-	mfld = folder_from_name (mse, folder_name, 0, FALSE);
-	if (!mfld)
-		return;
-
-	refresh_folder_internal (stub, mfld, FALSE);
-	if (!sync_deletions (mse, mfld)) {
-		/* sync_deletions didn't call this, thus call it now */
-		mail_stub_push_changes (stub);
-	}
-}
-
-static void
-expunge_uids (MailStub *stub, const gchar *folder_name, GPtrArray *uids)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	MailStubExchangeMessage *mmsg;
-	GPtrArray *hrefs;
-	E2kResultIter *iter;
-	E2kResult *result;
-	E2kHTTPStatus status;
-	gint i, ndeleted;
-	gboolean some_error = FALSE;
-
-	if (!uids->len) {
-		mail_stub_return_ok (stub);
-		return;
-	}
-
-	mfld = folder_from_name (mse, folder_name, MAPI_ACCESS_DELETE, FALSE);
-	if (!mfld)
-		return;
-
-	g_static_rec_mutex_lock (&g_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);
+		set_exception (ex, _("No such folder"));
+		return NULL;
 	}
 
-	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);
-		mail_stub_return_ok (stub);
-		g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-		return;
+	/* 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);
 	}
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FREEZE_FOLDER,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_END);
-
-	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 (stub, mfld, result->href);
-		mfld->deleted_count++;
-		ndeleted++;
-
-		mail_stub_return_progress (stub, ndeleted * 100 / hrefs->len);
+	if ((perms == MAPI_ACCESS_MODIFY || perms == MAPI_ACCESS_DELETE) &&
+	    !(mfld->access & perms)) {
+		/* try with MAPI_ACCESS_CREATE_CONTENTS */
+		perms = MAPI_ACCESS_CREATE_CONTENTS;
 	}
-	status = e2k_result_iter_free (iter);
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_THAW_FOLDER,
-			       CAMEL_STUB_ARG_FOLDER, mfld->name,
-			       CAMEL_STUB_ARG_END);
-
-	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
-		g_warning ("expunged: %d", status);
-		mail_stub_return_error (stub, _("Could not empty Deleted Items folder"));
-	} else if (some_error) {
-		mail_stub_return_error (stub, _("Permission denied. Could not delete certain messages."));
-	} else {
-		mail_stub_return_ok (stub);
+	if (perms && !(mfld->access & perms)) {
+		set_exception (ex, _("Permission denied"));
+		return NULL;
 	}
 
-	g_ptr_array_free (hrefs, TRUE);
+	mfld->last_activity = time (NULL);
+	return mfld;
 }
 
 static void
@@ -1686,193 +1342,16 @@ mark_read (EFolder *folder, GPtrArray *hrefs, gboolean read)
 }
 
 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;
-}
-
-static void
-append_message (MailStub *stub, const gchar *folder_name, guint32 flags,
-		const gchar *subject, const gchar *data, gint length)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	E2kHTTPStatus status;
-	gchar *ru_header = NULL, *repl_uid, *location = NULL;
-
-	mfld = folder_from_name (mse, folder_name, MAPI_ACCESS_CREATE_CONTENTS, FALSE);
-	if (!mfld)
-		return;
-
-	status = e_folder_exchange_put_new (mfld->folder, NULL, subject,
-					    test_uri, mfld->messages_by_href,
-					    "message/rfc822", data, length,
-					    &location, &ru_header);
-	if (status != E2K_HTTP_CREATED) {
-		g_warning ("appended_message: %d", status);
-		mail_stub_return_error (stub,
-					status == E2K_HTTP_INSUFFICIENT_SPACE_ON_RESOURCE ?
-					_("Could not append message; mailbox is over quota") :
-					_("Could not append message"));
-		return;
-	}
-
-	if (location) {
-		if (flags & MAIL_STUB_MESSAGE_SEEN)
-			mark_one_read (mse->ctx, location, TRUE);
-		else
-			mark_one_read (mse->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;
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_STRING, repl_uid ? uidstrip (repl_uid) : "",
-			       CAMEL_STUB_ARG_END);
-
-	g_free (repl_uid);
-	g_free (ru_header);
-	g_free (location);
-
-	mail_stub_return_ok (stub);
-}
-
-static inline void
-change_pending (MailStubExchangeFolder *mfld)
-{
-	if (!mfld->pending_delete_ops && !mfld->changed_messages->len)
-		g_object_ref (mfld->mse);
-}
-
-static inline void
-change_complete (MailStubExchangeFolder *mfld)
-{
-	if (!mfld->pending_delete_ops && !mfld->changed_messages->len)
-		g_object_unref (mfld->mse);
-}
-
-static void
-set_replied_flags (MailStubExchange *mse, MailStubExchangeMessage *mmsg)
-{
-	E2kProperties *props;
-	E2kHTTPStatus status;
-
-	props = e2k_properties_new ();
-
-	if (mmsg->change_flags & MAIL_STUB_MESSAGE_ANSWERED) {
-		e2k_properties_set_int (props, PR_ACTION, MAPI_ACTION_REPLIED);
-		e2k_properties_set_int (props, PR_ACTION_FLAG, (mmsg->change_flags & MAIL_STUB_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 (mse->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);
-}
-
-static void
-set_important_flag (MailStubExchange *mse, MailStubExchangeMessage *mmsg)
-{
-	E2kProperties *props;
-	E2kHTTPStatus status;
-
-	props = e2k_properties_new ();
-
-	if (mmsg->change_flags & MAIL_STUB_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 (mse->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);
-}
-
-static void
-update_tags (MailStubExchange *mse, MailStubExchangeMessage *mmsg)
-{
-	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 (mse->ctx, NULL, mmsg->href, props,
-					FALSE, NULL);
-	e2k_properties_free (props);
-	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
-		g_warning ("update_tags: %d", status);
-}
-
-static gboolean
 process_flags (gpointer user_data)
 {
-	MailStubExchangeFolder *mfld = user_data;
-	MailStubExchange *mse = mfld->mse;
-	MailStubExchangeMessage *mmsg;
+	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 (&g_changed_msgs_mutex);
+	g_static_rec_mutex_lock (&ed->changed_msgs_mutex);
 
 	for (i = 0; i < mfld->changed_messages->len; i++) {
 		mmsg = mfld->changed_messages->pdata[i];
@@ -1882,39 +1361,126 @@ process_flags (gpointer user_data)
 				   __LINE__, mfld->name, mfld->type));
 		}
 
-		if (mmsg->change_mask & MAIL_STUB_MESSAGE_SEEN) {
-			if (mmsg->change_flags & MAIL_STUB_MESSAGE_SEEN) {
+		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 |= MAIL_STUB_MESSAGE_SEEN;
+				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 &= ~MAIL_STUB_MESSAGE_SEEN;
+				mmsg->flags &= ~CAMEL_MESSAGE_SEEN;
 			}
-			mmsg->change_mask &= ~MAIL_STUB_MESSAGE_SEEN;
+			mmsg->change_mask &= ~CAMEL_MESSAGE_SEEN;
 		}
 
-		if (mmsg->change_mask & MAIL_STUB_MESSAGE_ANSWERED) {
-			set_replied_flags (mse, mmsg);
-			mmsg->change_mask &= ~(MAIL_STUB_MESSAGE_ANSWERED | MAIL_STUB_MESSAGE_ANSWERED_ALL);
+		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 & MAIL_STUB_MESSAGE_FLAGGED) {
-			set_important_flag (mse, mmsg);
-			mmsg->change_mask &= ~MAIL_STUB_MESSAGE_FLAGGED;
+		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)
-			update_tags (mse, mmsg);
+		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 (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
 
 	if (seen || unseen) {
 		if (seen) {
@@ -1930,39 +1496,38 @@ process_flags (gpointer user_data)
 
 		if (mfld->changed_messages->len == 0) {
 			mfld->flag_timeout = 0;
-			change_complete (mfld);
+			/* change_complete (mfld); */
 			return FALSE;
 		} else
 			return TRUE;
 	}
 
-	g_static_rec_mutex_lock (&g_changed_msgs_mutex);
+	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 & MAIL_STUB_MESSAGE_DELETED) {
+		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 (&g_changed_msgs_mutex);
+	g_static_rec_mutex_unlock (&ed->changed_msgs_mutex);
 
 	if (deleted) {
-		MailStub *stub = MAIL_STUB (mse);
+		CamelFolder *folder = get_camel_folder (mfld);
 		E2kResultIter *iter;
 		E2kResult *result;
 		E2kHTTPStatus status;
 
-		change_pending (mfld);
+		/* change_pending (mfld); */
 		mfld->pending_delete_ops++;
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FREEZE_FOLDER,
-				       CAMEL_STUB_ARG_FOLDER, mfld->name,
-				       CAMEL_STUB_ARG_END);
+		if (folder)
+			camel_folder_freeze (folder);
 
 		if (hier_type == EXCHANGE_HIERARCHY_PERSONAL) {
 			iter = e_folder_exchange_transfer_start (mfld->folder, NULL,
-								 mse->deleted_items,
+								 ed->deleted_items,
 								 deleted, TRUE);
 		} else {
 			/* This is for public folder hierarchy. We cannot move
@@ -1982,175 +1547,54 @@ process_flags (gpointer user_data)
 					continue;
 				}
 			} else if (result->status == E2K_HTTP_UNAUTHORIZED) {
-				mail_stub_return_data (MAIL_STUB (mfld->mse),
-						       CAMEL_STUB_RETVAL_CHANGED_FLAGS_EX,
-						       CAMEL_STUB_ARG_FOLDER, mfld->name,
-						       CAMEL_STUB_ARG_STRING, mmsg->uid,
-						       CAMEL_STUB_ARG_UINT32, 0,
-						       CAMEL_STUB_ARG_UINT32, MAIL_STUB_MESSAGE_DELETED,
-						       CAMEL_STUB_ARG_END);
+				camel_exchange_folder_update_message_flags_ex (CAMEL_EXCHANGE_FOLDER (folder), mmsg->uid, 0, CAMEL_MESSAGE_DELETED);
 				continue;
 			}
 
-			message_removed (stub, mfld, result->href);
+			message_removed (mfld, folder, result->href);
 			mfld->deleted_count++;
 		}
 		status = e2k_result_iter_free (iter);
 
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_THAW_FOLDER,
-				       CAMEL_STUB_ARG_FOLDER, mfld->name,
-				       CAMEL_STUB_ARG_END);
+		if (folder)
+			camel_folder_thaw (folder);
 
 		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
 			g_warning ("deleted: %d", status);
 
-		mail_stub_push_changes (stub);
 		mfld->pending_delete_ops--;
-		change_complete (mfld);
+		/* change_complete (mfld); */
 	}
 
 	if (mfld->changed_messages->len) {
 		g_ptr_array_set_size (mfld->changed_messages, 0);
-		change_complete (mfld);
+		/* change_complete (mfld); */
 	}
-	mfld->flag_timeout = 0;
-	return FALSE;
-}
 
-static void
-change_message (MailStubExchange *mse, MailStubExchangeFolder *mfld,
-		MailStubExchangeMessage *mmsg)
-{
-	gint i;
-
-	g_static_rec_mutex_lock (&g_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);
-		g_ptr_array_add (mfld->changed_messages, mmsg);
-	}
-	g_static_rec_mutex_unlock (&g_changed_msgs_mutex);
-
-	if (mfld->flag_timeout)
-		g_source_remove (mfld->flag_timeout);
-	mfld->flag_timeout = g_timeout_add (1000, process_flags, mfld);
-}
-
-static void
-set_message_flags (MailStub *stub, const gchar *folder_name, const gchar *uid,
-		   guint32 flags, guint32 mask)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	MailStubExchangeMessage *mmsg;
-
-	mfld = folder_from_name (mse, folder_name, MAPI_ACCESS_MODIFY, TRUE);
-	if (!mfld)
-		return;
-
-	mmsg = find_message (mfld, uid);
-	if (!mmsg)
-		return;
-
-	/* 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 & MAIL_STUB_MESSAGE_SEEN) {
-		if (((mmsg->flags ^ flags) & MAIL_STUB_MESSAGE_SEEN) == 0) {
-			/* The user is just setting it to what it
-			 * already is, so ignore it.
-			 */
-			mask &= ~MAIL_STUB_MESSAGE_SEEN;
-		} else {
-			mmsg->flags ^= MAIL_STUB_MESSAGE_SEEN;
-			if (mmsg->flags & MAIL_STUB_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 stub 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 & MAIL_STUB_MESSAGE_DELETED) {
-		ExchangeHierarchy *hier;
-
-		hier = e_folder_exchange_get_hierarchy (mfld->folder);
-		if (hier->type != EXCHANGE_HIERARCHY_PERSONAL)
-			mask &= ~MAIL_STUB_MESSAGE_DELETED;
-	}
-#endif
-
-	/* If there's nothing left to change, return. */
-	if (!mask)
-		return;
-
-	mmsg->change_flags |= (flags & mask);
-	mmsg->change_flags &= ~(~flags & mask);
-	mmsg->change_mask |= mask;
-
-	change_message (mse, mfld, mmsg);
-}
-
-static void
-set_message_tag (MailStub *stub, const gchar *folder_name, const gchar *uid,
-		 const gchar *name, const gchar *value)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	MailStubExchangeMessage *mmsg;
-
-	mfld = folder_from_name (mse, folder_name, MAPI_ACCESS_MODIFY, TRUE);
-	if (!mfld)
-		return;
-
-	mmsg = find_message (mfld, uid);
-	if (!mmsg)
-		return;
+	mfld->flag_timeout = 0;
 
-	g_datalist_set_data_full (&mmsg->tag_updates, name,
-				  g_strdup (value), g_free);
-	change_message (mse, mfld, mmsg);
+	return FALSE;
 }
 
-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,
-};
-static const gint n_stickynote_props = sizeof (stickynote_props) / sizeof (stickynote_props[0]);
-
 static E2kHTTPStatus
-get_stickynote (E2kContext *ctx, E2kOperation *op, const gchar *uri,
-		gchar **body, gint *len)
+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, n_stickynote_props,
+				       stickynote_props, G_N_ELEMENTS (stickynote_props),
 				       &results, &nresults);
 
 	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
@@ -2165,9 +1609,7 @@ get_stickynote (E2kContext *ctx, E2kOperation *op, const gchar *uri,
 }
 
 static E2kHTTPStatus
-build_message_from_document (E2kContext *ctx, E2kOperation *op,
-			     const gchar *uri,
-			     gchar **body, gint *len)
+build_message_from_document (E2kContext *ctx, E2kOperation *op, const gchar *uri, gchar **body, gint *len)
 {
 	E2kHTTPStatus status;
 	E2kResult *results;
@@ -2175,10 +1617,7 @@ build_message_from_document (E2kContext *ctx, E2kOperation *op,
 	GString *message;
 	gchar *headers;
 
-	status = e2k_context_propfind (ctx, op, uri,
-				       mapi_message_props,
-				       n_mapi_message_props,
-				       &results, &nresults);
+	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)
@@ -2200,9 +1639,7 @@ build_message_from_document (E2kContext *ctx, E2kOperation *op,
 }
 
 static E2kHTTPStatus
-unmangle_delegated_meeting_request (MailStubExchange *mse, E2kOperation *op,
-				    const gchar *uri,
-				    gchar **body, gint *len)
+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;
@@ -2217,8 +1654,7 @@ unmangle_delegated_meeting_request (MailStubExchange *mse, E2kOperation *op,
 	gint nresults = 0;
 	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_DELGATED_MEETING;
 
-	status = e2k_context_propfind (mse->ctx, op, uri, &prop, 1,
-				       &results, &nresults);
+	status = e2k_context_propfind (ed->ctx, op, uri, &prop, 1, &results, &nresults);
 	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
 		return status;
 	if (!nresults)
@@ -2230,7 +1666,7 @@ unmangle_delegated_meeting_request (MailStubExchange *mse, E2kOperation *op,
 		return E2K_HTTP_OK;
 	}
 
-	account = mse->account;
+	account = ed->account;
 	gc = exchange_account_get_global_catalog (account);
 	if (!gc) {
 		g_warning ("\nNo GC: could not unmangle meeting request");
@@ -2277,10 +1713,38 @@ unmangle_delegated_meeting_request (MailStubExchange *mse, E2kOperation *op,
 	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 (MailStubExchange *mse,
-					      const gchar *delegator_email,
-					      gchar **body, gint *len)
+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;
@@ -2291,7 +1755,7 @@ unmangle_meeting_request_in_subscribed_inbox (MailStubExchange *mse,
 	EFolder *folder = NULL;
 	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_MEETING_IN_SUBSCRIBED_INBOX;
 
-	account = mse->account;
+	account = ed->account;
 	gc = exchange_account_get_global_catalog (account);
 	if (!gc) {
 		g_warning ("\nNo GC: could not unmangle meeting request in subscribed folder");
@@ -2336,9 +1800,7 @@ unmangle_meeting_request_in_subscribed_inbox (MailStubExchange *mse,
 }
 
 static E2kHTTPStatus
-unmangle_sender_field (MailStubExchange *mse, E2kOperation *op,
-				    const gchar *uri,
-				    gchar **body, gint *len)
+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;
@@ -2353,8 +1815,7 @@ unmangle_sender_field (MailStubExchange *mse, E2kOperation *op,
 	gint nresults = 0;
 	MailUtilDemangleType unmangle_type = MAIL_UTIL_DEMANGLE_SENDER_FIELD;
 
-	status = e2k_context_propfind (mse->ctx, op, uri, props, 2,
-				       &results, &nresults);
+	status = e2k_context_propfind (ed->ctx, op, uri, props, 2, &results, &nresults);
 	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
 		return status;
 	if (!nresults)
@@ -2377,7 +1838,7 @@ unmangle_sender_field (MailStubExchange *mse, E2kOperation *op,
 		return E2K_HTTP_OK;
 	}
 
-	account = mse->account;
+	account = ed->account;
 	gc = exchange_account_get_global_catalog (account);
 	if (!gc) {
 		g_warning ("\nNo GC: could not unmangle sender field");
@@ -2425,73 +1886,752 @@ unmangle_sender_field (MailStubExchange *mse, E2kOperation *op,
 	return E2K_HTTP_OK;
 }
 
-static gboolean
-is_foreign_folder (MailStub *stub, const gchar *folder_name, gchar **owner_email)
+static void
+get_folder_info_data (ExchangeData *ed, const gchar *top, guint32 store_flags, GPtrArray **names, GPtrArray **uris, GArray **unread, GArray **flags)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	EFolder *folder;
+	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;
+	gint mode;
+
+	g_return_val_if_fail (ed != NULL, FALSE);
+	g_return_val_if_fail (status != NULL, FALSE);
+
+	mode = is_online (ed);
+
+	account = ed->account;
+	if (mode == ONLINE_MODE)
+		exchange_account_set_online (account);
+	else if (mode == OFFLINE_MODE)
+		exchange_account_set_offline (account);
+
+	ctx = exchange_account_get_context (account);
+	if (!ctx) {
+		ctx = exchange_account_connect (account, pwd, &result);
+	}
+
+	if (!ctx && mode == ONLINE_MODE) {
+		retval = 0;
+		goto end;
+	} else if (mode == 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 */
+
+	g_hash_table_foreach (ed->folders_by_name,
+			      (GHFunc) folder_update_linestatus,
+			      GINT_TO_POINTER (mode));
+ 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;
 
-	path = g_build_filename ("/", folder_name, NULL);
-	folder = exchange_account_get_folder (mse->account, path);
-	if (!folder) {
+	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;
 
-	hier = e_folder_exchange_get_hierarchy (folder);
+	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;
+	}
 
-	if (hier->type != EXCHANGE_HIERARCHY_FOREIGN) {
-		g_object_unref (folder);
+	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;
 	}
 
-	*owner_email = g_strdup (hier->owner_email);
+	*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);
 
-	g_object_unref (folder);
 	return TRUE;
 }
 
 static void
-get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
+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)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
-	MailStubExchangeMessage *mmsg;
+	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 (mse, folder_name, MAPI_ACCESS_READ, FALSE);
+	mfld = folder_from_name (ed, folder_name, MAPI_ACCESS_READ, ex);
 	if (!mfld)
-		return;
+		return FALSE;
+
+	folder = get_camel_folder (mfld);
 
 	mmsg = find_message (mfld, uid);
 	if (!mmsg) {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_REMOVED_MESSAGE,
-				       CAMEL_STUB_ARG_FOLDER, folder_name,
-				       CAMEL_STUB_ARG_STRING, uid,
-				       CAMEL_STUB_ARG_END);
-		mail_stub_return_error (stub, _("No such message"));
-		return;
+		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 == MAIL_STUB_EXCHANGE_FOLDER_NOTES) {
-		status = get_stickynote (mse->ctx, NULL, mmsg->href,
-					 &body, &len);
+	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 (mse->ctx, NULL, mmsg->href,
-					  &content_type, &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);
@@ -2503,9 +2643,7 @@ get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
 	 * courtesy of mp:x67200102.
 	 */
 	if (!content_type || g_ascii_strncasecmp (content_type, "message/", 8)) {
-		status = build_message_from_document (mse->ctx, NULL,
-						      mmsg->href,
-						      &body, &len);
+		status = build_message_from_document (ed->ctx, NULL, mmsg->href, &body, &len);
 		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
 			goto error;
 	}
@@ -2513,10 +2651,8 @@ get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
 	/* If this is a delegated meeting request, we need to know who
 	 * delegated it to us.
 	 */
-	if (mmsg->flags & MAIL_STUB_MESSAGE_DELEGATED) {
-		status = unmangle_delegated_meeting_request (mse, NULL,
-							     mmsg->href,
-							     &body, &len);
+	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;
 	}
@@ -2524,11 +2660,8 @@ get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
 	/* If the message is in a subscribed inbox,
 	 * we need to modify the message appropriately.
 	 */
-	if (is_foreign_folder (stub, folder_name, &owner_email)) {
-
-		status = unmangle_meeting_request_in_subscribed_inbox  (mse,
-									owner_email,
-									&body, &len);
+	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;
 	}
@@ -2536,16 +2669,15 @@ get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
 	/* If there is a sender field in the meeting request/response,
 	 * we need to know who it is.
 	 */
-	status = unmangle_sender_field (mse, NULL,
-					mmsg->href,
-					&body, &len);
+	status = unmangle_sender_field (ed, NULL, mmsg->href, &body, &len);
 	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
 		goto error;
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_BYTEARRAY, body, len,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
+	*message_bytes = g_byte_array_sized_new (len);
+	g_byte_array_append (*message_bytes, (const guint8 *)body, len);
+
+	res = TRUE;
+
 	goto cleanup;
 
  error:
@@ -2555,22 +2687,28 @@ get_message (MailStub *stub, const gchar *folder_name, const gchar *uid)
 		 * message may actually have gone away before the last
 		 * time we recorded that.
 		 */
-		message_removed (stub, mfld, mmsg->href);
-		mail_stub_return_error (stub, _("Message has been deleted"));
+		message_removed (mfld, folder, mmsg->href);
+		set_exception (ex, _("Message has been deleted"));
 	} else
-		mail_stub_return_error (stub, _("Error retrieving message"));
+		set_exception (ex, _("Error retrieving message"));
 
-cleanup:
+ cleanup:
 	g_free (body);
 	g_free (content_type);
 	g_free (owner_email);
+
+	return res;
 }
 
-static void
-search (MailStub *stub, const gchar *folder_name, const gchar *text)
+gboolean
+camel_exchange_utils_search (CamelService *service,
+				const gchar *folder_name,
+				const gchar *text,
+				GPtrArray **found_uids, /* out */
+				CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *mfld;
 	E2kRestriction *rn;
 	const gchar *prop, *repl_uid;
 	E2kResultIter *iter;
@@ -2578,47 +2716,53 @@ search (MailStub *stub, const gchar *folder_name, const gchar *text)
 	E2kHTTPStatus status;
 	GPtrArray *matches;
 
-	mfld = folder_from_name (mse, folder_name, 0, FALSE);
+	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;
+		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);
+	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);
+		repl_uid = e2k_properties_get_prop (result->props, E2K_PR_REPL_UID);
 		if (repl_uid)
-			g_ptr_array_add (matches, (gchar *)uidstrip (repl_uid));
+			g_ptr_array_add (matches, g_strdup (uidstrip (repl_uid)));
 	}
 	status = e2k_result_iter_free (iter);
 
 	if (status == E2K_HTTP_UNPROCESSABLE_ENTITY) {
-		mail_stub_return_error (stub, _("Mailbox does not support full-text searching"));
+		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 {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-				       CAMEL_STUB_ARG_STRINGARRAY, matches,
-				       CAMEL_STUB_ARG_END);
-		mail_stub_return_ok (stub);
+		*found_uids = matches;
 	}
 
-	g_ptr_array_free (matches, TRUE);
+	return matches != NULL;
 }
 
-static void
-transfer_messages (MailStub *stub, const gchar *source_name,
-		   const gchar *dest_name, GPtrArray *uids,
-		   gboolean delete_originals)
+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)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *source, *dest;
-	MailStubExchangeMessage *mmsg;
+	ExchangeData *ed = get_data_for_service (service);
+	ExchangeFolder *source, *dest;
+	ExchangeMessage *mmsg;
 	GPtrArray *hrefs, *new_uids;
 	GHashTable *order;
 	gpointer key, value;
@@ -2627,13 +2771,17 @@ transfer_messages (MailStub *stub, const gchar *source_name,
 	E2kHTTPStatus status;
 	const gchar *uid;
 	gint i, num;
+	CamelFolder *folder;
 
-	source = folder_from_name (mse, source_name, delete_originals ? MAPI_ACCESS_DELETE : 0, FALSE);
+	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;
-	dest = folder_from_name (mse, dest_name, MAPI_ACCESS_CREATE_CONTENTS, FALSE);
+		return FALSE;
+	dest = folder_from_name (ed, dest_name, MAPI_ACCESS_CREATE_CONTENTS, ex);
 	if (!dest)
-		return;
+		return FALSE;
 
 	order = g_hash_table_new (NULL, NULL);
 	hrefs = g_ptr_array_new ();
@@ -2650,13 +2798,13 @@ transfer_messages (MailStub *stub, const gchar *source_name,
 
 		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, (gpointer) "");
+		g_ptr_array_add (new_uids, g_strdup (""));
 	}
 
-	if (delete_originals && hrefs->len > 1) {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FREEZE_FOLDER,
-				       CAMEL_STUB_ARG_FOLDER, source->name,
-				       CAMEL_STUB_ARG_END);
+	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,
@@ -2683,47 +2831,47 @@ transfer_messages (MailStub *stub, const gchar *source_name,
 		if (num > new_uids->len)
 			continue;
 
-		new_uids->pdata[num] = (gchar *)uidstrip (uid);
+		g_free (new_uids->pdata[num]);
+		new_uids->pdata[num] = g_strdup (uidstrip (uid));
 
 		if (delete_originals)
-			message_removed (stub, source, result->href);
+			message_removed (source, folder, result->href);
 	}
 	status = e2k_result_iter_free (iter);
 
-	if (delete_originals && hrefs->len > 1) {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_THAW_FOLDER,
-				       CAMEL_STUB_ARG_FOLDER, source->name,
-				       CAMEL_STUB_ARG_END);
+	if (delete_originals && hrefs->len > 1 && folder) {
+		camel_folder_thaw (folder);
 	}
 
 	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-				       CAMEL_STUB_ARG_STRINGARRAY, new_uids,
-				       CAMEL_STUB_ARG_END);
-		mail_stub_return_ok (stub);
+		*ret_uids = new_uids;
 	} else {
 		g_warning ("transferred_messages: %d", status);
-		mail_stub_return_error (stub, _("Unable to move/copy messages"));
+		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_ptr_array_free (new_uids, TRUE);
 	g_hash_table_destroy (order);
+
+	return new_uids != NULL;
 }
 
 static void
 account_new_folder (ExchangeAccount *account, EFolder *folder, gpointer user_data)
 {
-	MailStub *stub = user_data;
-	MailStubExchange *mse = 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 (mse->ignore_new_folder &&
-	    !strcmp (e_folder_exchange_get_path (folder), mse->ignore_new_folder))
+	if (ed->ignore_new_folder &&
+	    !strcmp (e_folder_exchange_get_path (folder), ed->ignore_new_folder))
 		return;
 
 	hier = e_folder_exchange_get_hierarchy (folder);
@@ -2732,27 +2880,23 @@ account_new_folder (ExchangeAccount *account, EFolder *folder, gpointer user_dat
 	    hier->type != EXCHANGE_HIERARCHY_FOREIGN)
 		return;
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FOLDER_CREATED,
-			       CAMEL_STUB_ARG_STRING, e_folder_get_name (folder),
-			       CAMEL_STUB_ARG_STRING, e_folder_get_physical_uri (folder),
-			       CAMEL_STUB_ARG_END);
-
-	mail_stub_push_changes (stub);
+	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)
 {
-	MailStub *stub = user_data;
-	MailStubExchange *mse = 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 (mse->ignore_removed_folder &&
-	    !strcmp (e_folder_exchange_get_path (folder), mse->ignore_removed_folder))
+	if (ed->ignore_removed_folder &&
+	    !strcmp (e_folder_exchange_get_path (folder), ed->ignore_removed_folder))
 		return;
 
 	hier = e_folder_exchange_get_hierarchy (folder);
@@ -2761,224 +2905,68 @@ account_removed_folder (ExchangeAccount *account, EFolder *folder, gpointer user
 	    hier->type != EXCHANGE_HIERARCHY_FOREIGN)
 		return;
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FOLDER_DELETED,
-			       CAMEL_STUB_ARG_STRING, e_folder_get_name (folder),
-			       CAMEL_STUB_ARG_STRING, e_folder_get_physical_uri (folder),
-			       CAMEL_STUB_ARG_END);
-
-	mail_stub_push_changes (stub);
-}
-
-static void
-get_folder_info_data (MailStub *stub, const gchar *top, guint32 store_flags,
-		      GPtrArray **names, GPtrArray **uris,
-		      GArray **unread, GArray **flags)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	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_STUB_STORE_FOLDER_INFO_RECURSIVE);
-	subscribed = (store_flags & CAMEL_STUB_STORE_FOLDER_INFO_SUBSCRIBED);
-	subscription_list = (store_flags & CAMEL_STUB_STORE_FOLDER_INFO_SUBSCRIPTION_LIST);
-
-	exchange_account_is_offline (mse->account, &mode);
-	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 (mse->account, "/public");
-		if (result ==  EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST) {
-			hier = exchange_account_get_hierarchy_by_type (mse->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 (mse->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 (mse->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 (mse->inbox) {
-		inbox_uri = e_folder_get_physical_uri (mse->inbox);
-	}
-
-	if (mse->deleted_items) {
-		trash_uri = e_folder_get_physical_uri (mse->deleted_items);
-	}
-
-	if (mse->sent_items) {
-		sent_items_uri = e_folder_get_physical_uri (mse->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_STUB_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 (mse->account, folder)) {
-						folder_flags |= CAMEL_STUB_FOLDER_SUBSCRIBED;
-						d(printf ("marked the folder as subscribed\n"));
-					}
-					break;
-				case EXCHANGE_HIERARCHY_FOREIGN:
-					if (folder_flags & CAMEL_STUB_FOLDER_NOSELECT &&
-					    mse->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_STUB_FOLDER_SYSTEM|CAMEL_STUB_FOLDER_TYPE_INBOX;
-
-			if (trash_uri && !strcmp (uri, trash_uri))
-				folder_flags |= CAMEL_STUB_FOLDER_SYSTEM|CAMEL_STUB_FOLDER_TYPE_TRASH;
-
-			if (sent_items_uri && !strcmp (uri, sent_items_uri))
-				folder_flags |= CAMEL_STUB_FOLDER_SYSTEM|CAMEL_STUB_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_STUB_FOLDER_NOCHILDREN;
-			}
-
-			d(g_print ("folder flags is : %d\n", folder_flags));
-
-			g_ptr_array_add (*names, (gchar *)name);
-			g_ptr_array_add (*uris, (gchar *)uri);
-			g_array_append_val (*unread, unread_count);
-			g_array_append_val (*flags, folder_flags);
-		}
-
-		g_ptr_array_free (folders, TRUE);
-	}
+	camel_exchange_store_folder_deleted (ed->estore, e_folder_get_name (folder), e_folder_get_physical_uri (folder));
 }
 
-static void
-get_folder_info (MailStub *stub, const gchar *top, guint32 store_flags)
+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)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	GPtrArray *names, *uris;
-	GArray *unread, *flags;
-
-	get_folder_info_data (stub, top, store_flags, &names, &uris,
-			      &unread, &flags);
+	ExchangeData *ed = get_data_for_service (service);
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_STRINGARRAY, names,
-			       CAMEL_STUB_ARG_STRINGARRAY, uris,
-			       CAMEL_STUB_ARG_UINT32ARRAY, unread,
-			       CAMEL_STUB_ARG_UINT32ARRAY, flags,
-			       CAMEL_STUB_ARG_END);
+	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);
 
-	g_ptr_array_free (names, TRUE);
-	g_ptr_array_free (uris, TRUE);
-	g_array_free (unread, TRUE);
-	g_array_free (flags, TRUE);
+	get_folder_info_data (ed, top, store_flags, folder_names, folder_uris, unread_counts, folder_flags);
 
-	if (mse->new_folder_id == 0) {
-		mse->new_folder_id = g_signal_connect (
-			mse->account, "new_folder",
-			G_CALLBACK (account_new_folder), stub);
-		mse->removed_folder_id = g_signal_connect (
-			mse->account, "removed_folder",
-			G_CALLBACK (account_removed_folder), stub);
+	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);
 	}
 
-	mail_stub_return_ok (stub);
+	return TRUE;
 }
 
-static void
-send_message (MailStub *stub, const gchar *from, GPtrArray *recipients,
-	      const gchar *body, gint length)
+gboolean
+camel_exchange_utils_send_message (CamelService *service,
+				const gchar *from,
+				GPtrArray *recipients,
+				const GByteArray *message,
+				CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	ExchangeData *ed = get_data_for_service (service);
 	SoupMessage *msg;
 	E2kHTTPStatus status;
 	gchar *timestamp, *errmsg;
 	GString *data;
 	gint i;
+	gboolean res = FALSE;
 
-	if (!mse->mail_submission_uri) {
-		mail_stub_return_error (stub, _("No mail submission URI for this mailbox"));
-		return;
+	/* 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_printf (data, "RCPT TO:<%s>\r\n", (gchar *)recipients->pdata[i]);
 	}
 	g_string_append (data, "\r\n");
 
@@ -2987,29 +2975,29 @@ send_message (MailStub *stub, const gchar *from, GPtrArray *recipients,
 	 */
 	timestamp = e2k_make_timestamp_rfc822 (time (NULL));
 	g_string_append_printf (data, "Received: from %s by %s; %s\r\n",
-				g_get_host_name (), mse->account->exchange_server,
+				g_get_host_name (), ed->account->exchange_server,
 				timestamp);
 	g_free (timestamp);
 
-	g_string_append_len (data, body, length);
+	g_string_append_len (data, (const gchar *)message->data, message->len);
 
-	msg = e2k_soup_message_new_full (mse->ctx, mse->mail_submission_uri,
+	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 (mse->ctx, NULL, msg);
-	if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
-		mail_stub_return_ok (stub);
-	else if (status == E2K_HTTP_NOT_FOUND)
-		mail_stub_return_error (stub, _("Server won't accept mail via Exchange transport"));
-	else if (status == E2K_HTTP_FORBIDDEN) {
+	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);
-		mail_stub_return_error (stub, errmsg);
+		set_exception (ex, errmsg);
 		g_free (errmsg);
 	} else if (status == E2K_HTTP_INSUFFICIENT_SPACE_ON_RESOURCE ||
 		   status == E2K_HTTP_INTERNAL_SERVER_ERROR) {
@@ -3018,25 +3006,38 @@ send_message (MailStub *stub, const gchar *from, GPtrArray *recipients,
 		 * changes in the future.)
 		 */
 		E2K_KEEP_PRECEDING_COMMENT_OUT_OF_PO_FILES;
-		mail_stub_return_error (stub, _("Could not send message.\n"
-						"This might mean that your account is over quota."));
+		set_exception (ex, _("Could not send message.\n"
+				     "This might mean that your account is over quota."));
 	} else {
 		g_warning ("sent_message: %d", status);
-		mail_stub_return_error (stub, _("Could not send message"));
+		set_exception (ex, _("Could not send message"));
 	}
+
+	return res;
 }
 
-static void
-create_folder (MailStub *stub, const gchar *parent_name, const gchar *folder_name)
+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)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	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 (mse->account, path, "mail");
-	folder = exchange_account_get_folder (mse->account, path);
+	result = exchange_account_create_folder (ed->account, path, "mail");
+	folder = exchange_account_get_folder (ed->account, path);
 	g_free (path);
 
 	switch (result) {
@@ -3045,104 +3046,121 @@ create_folder (MailStub *stub, const gchar *parent_name, const gchar *folder_nam
 			break;
 		/* fall through */
 	default:
-		mail_stub_return_error (stub, _("Generic error"));
-		return;
+		set_exception (ex, _("Generic error"));
+		return FALSE;
 
 	case EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS:
-		mail_stub_return_error (stub, _("Folder already exists"));
-		return;
+		set_exception (ex, _("Folder already exists"));
+		return FALSE;
 
 	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
-		mail_stub_return_error (stub, _("Permission denied"));
-		return;
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
 	}
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_STRING, e_folder_get_physical_uri (folder),
-			       CAMEL_STUB_ARG_UINT32, e_folder_get_unread_count (folder),
-			       CAMEL_STUB_ARG_UINT32, 0,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
+	*folder_uri = g_strdup (e_folder_get_physical_uri (folder));
+	*unread_count = e_folder_get_unread_count (folder);
+	*flags = 0;
+
+	return TRUE;
 }
 
-static void
-delete_folder (MailStub *stub, const gchar *folder_name)
+gboolean
+camel_exchange_utils_delete_folder (CamelService *service,
+				const gchar *folder_name,
+				CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	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 (mse->account, path);
+	folder = exchange_account_get_folder (ed->account, path);
 	if (!folder) {
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
+		set_exception (ex, _("Folder doesn't exist"));
 		g_free (path);
-		return;
+		return FALSE;
 	}
 	g_object_ref (folder);
 
-	result = exchange_account_remove_folder (mse->account, path);
+	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 (mse->folders_by_name, folder_name);
+		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:
-		mail_stub_return_error (stub, _("Permission denied"));
+		set_exception (ex, _("Permission denied"));
 		g_object_unref (folder);
-		return;
+		return FALSE;
 
 	default:
-		mail_stub_return_error (stub, _("Generic error"));
+		set_exception (ex, _("Generic error"));
 		g_object_unref (folder);
-		return;
+		return FALSE;
 
 	}
 
 	g_object_unref (folder);
-	mail_stub_return_ok (stub);
+
+	return TRUE;
 }
 
-static void
-rename_folder (MailStub *stub, const gchar *old_name, const gchar *new_name)
+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)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	MailStubExchangeFolder *mfld;
+	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, mode;
+	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 (mse->account, old_path);
+	folder = exchange_account_get_folder (ed->account, old_path);
 	if (!folder) {
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
+		set_exception (ex, _("Folder doesn't exist"));
 		g_free (old_path);
-		return;
+		return FALSE;
 	}
 	new_path = g_build_filename ("/", new_name, NULL);
 
-	mse->ignore_removed_folder = old_path;
-	mse->ignore_new_folder = new_path;
-	result = exchange_account_xfer_folder (mse->account, old_path, new_path, TRUE);
-	folder = exchange_account_get_folder (mse->account, new_path);
-	mse->ignore_new_folder = mse->ignore_removed_folder = 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 (mse->folders_by_name, old_name);
+		mfld = g_hash_table_lookup (ed->folders_by_name, old_name);
 		if (!mfld)
 			break;
 
@@ -3150,25 +3168,23 @@ rename_folder (MailStub *stub, const gchar *old_name, const gchar *new_name)
 		mfld->folder = g_object_ref (folder);
 		mfld->name = e_folder_exchange_get_path (folder) + 1;
 
-		g_hash_table_steal (mse->folders_by_name, old_name);
-		g_hash_table_insert (mse->folders_by_name, (gchar *)mfld->name, mfld);
+		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 (stub, new_name, CAMEL_STUB_STORE_FOLDER_INFO_SUBSCRIBED,
-				      &names, &uris, &unread, &flags);
+		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++) {
-			MailStubExchangeMessage *mmsg;
+			ExchangeMessage *mmsg;
 			mmsg = mfld->messages->pdata[i];
 			g_free (mmsg->href);
 			mmsg->href = NULL;
 		}
 
-		exchange_component_is_offline (global_exchange_component, &mode);
-		if (mode == ONLINE_MODE) {
-			if (!get_folder_online (mfld, TRUE)) {
-				return;
+		if (is_online (ed) == ONLINE_MODE) {
+			if (!get_folder_online (mfld, ex)) {
+				return FALSE;
 			}
 		}
 
@@ -3194,9 +3210,9 @@ rename_folder (MailStub *stub, const gchar *old_name, const gchar *new_name)
 
 			old_name_remove = g_build_filename (old_name, "/", folder_name[1], NULL);
 
-			mfld = g_hash_table_lookup (mse->folders_by_name, old_name_remove);
+			mfld = g_hash_table_lookup (ed->folders_by_name, old_name_remove);
 
-			/* If the lookup for the MailStubExchangeFolder doesn't succeed then do
+			/* 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);
@@ -3206,103 +3222,98 @@ rename_folder (MailStub *stub, const gchar *old_name, const gchar *new_name)
 			new_path = g_build_filename ("/", new_name_mod, folder_name[1], NULL);
 			old_path = g_build_filename ("/", old_name_remove, NULL);
 
-			mse->ignore_removed_folder = old_path;
-			mse->ignore_new_folder = new_path;
-			result = exchange_account_xfer_folder (mse->account, old_path, new_path, TRUE);
-			folder = exchange_account_get_folder (mse->account, new_path);
-			mse->ignore_new_folder = mse->ignore_removed_folder = 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 (mse->folders_by_name, old_name_remove);
-			g_hash_table_insert (mse->folders_by_name, (gchar *)mfld->name, mfld);
+			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++) {
-				MailStubExchangeMessage *mmsg;
+				ExchangeMessage *mmsg;
 				mmsg = mfld->messages->pdata[j];
 				g_free (mmsg->href);
 				mmsg->href = NULL;
 			}
 
-			exchange_component_is_offline (global_exchange_component, &mode);
-			if (mode == ONLINE_MODE) {
-				if (!get_folder_online (mfld, TRUE)) {
-					return;
+			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);
+ cont_free:		g_free (new_name_mod);
 			g_free (uri_unescaped);
 			g_strfreev (folder_name);
 		}
 
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-				       CAMEL_STUB_ARG_STRINGARRAY, names,
-				       CAMEL_STUB_ARG_STRINGARRAY, uris,
-				       CAMEL_STUB_ARG_UINT32ARRAY, unread,
-				       CAMEL_STUB_ARG_UINT32ARRAY, flags,
-				       CAMEL_STUB_ARG_END);
-
-		g_ptr_array_free (names, TRUE);
-		g_ptr_array_free (uris, TRUE);
-		g_array_free (unread, TRUE);
-		g_array_free (flags, TRUE);
+		*folder_names = names;
+		*folder_uris = uris;
+		*unread_counts = unread;
+		*folder_flags = flags;
 		break;
 
 	case EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST:
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
-		return;
+		set_exception (ex, _("Folder doesn't exist"));
+		return FALSE;
 
 	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
-		mail_stub_return_error (stub, _("Permission denied"));
-		return;
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
 
 	default:
-		mail_stub_return_error (stub, _("Generic error"));
-		return;
+		set_exception (ex, _("Generic error"));
+		return FALSE;
 
 	}
 
-	mail_stub_return_ok (stub);
+	return TRUE;
 }
 
-static void
-subscribe_folder (MailStub *stub, const gchar *folder_name)
+gboolean
+camel_exchange_utils_subscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	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 (mse->account, path);
+	folder = exchange_account_get_folder (ed->account, path);
 	if (!folder) {
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
+		set_exception (ex, _("Folder doesn't exist"));
 		g_free (path);
-		return;
+		return FALSE;
 	}
 	g_free (path);
 	g_object_ref (folder);
 
 	if (e_folder_exchange_get_hierarchy (folder)->type != EXCHANGE_HIERARCHY_PUBLIC) {
 		g_object_unref (folder);
-		mail_stub_return_ok (stub);
-		return;
+		return TRUE;
 	}
 
 	if (!strcmp (e_folder_get_type_string (folder), "noselect")) {
 		g_object_unref (folder);
-		mail_stub_return_ok (stub);
-		return;
+		return TRUE;
 	}
 
-	result = exchange_account_add_favorite (mse->account, folder);
+	result = exchange_account_add_favorite (ed->account, folder);
+	g_object_unref (folder);
 
 	switch (result) {
 	case EXCHANGE_ACCOUNT_FOLDER_OK:
@@ -3310,35 +3321,35 @@ subscribe_folder (MailStub *stub, const gchar *folder_name)
 		break;
 
 	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
-		mail_stub_return_error (stub, _("Permission denied"));
-		g_object_unref (folder);
-		return;
+		set_exception (ex, _("Permission denied"));
+		return FALSE;
 
 	default:
-		mail_stub_return_error (stub, _("Generic error"));
-		g_object_unref (folder);
-		return;
+		set_exception (ex, _("Generic error"));
+		return FALSE;
 	}
 
-	g_object_unref (folder);
-	mail_stub_return_ok (stub);
+	return TRUE;
 }
 
-static void
-unsubscribe_folder (MailStub *stub, const gchar *folder_name)
+gboolean
+camel_exchange_utils_unsubscribe_folder (CamelService *service,
+					const gchar *folder_name,
+					CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	ExchangeData *ed = get_data_for_service (service);
 	ExchangeAccountFolderResult result;
 	EFolder *folder;
 	gchar *path, *pub_name;
 
-	d(printf ("unsubscribe folder : %s\n", folder_name));
+	g_return_val_if_fail (ed != NULL, FALSE);
+
 	path = g_build_filename ("/", folder_name, NULL);
-	folder = exchange_account_get_folder (mse->account, path);
+	folder = exchange_account_get_folder (ed->account, path);
 	if (!folder) {
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
+		set_exception (ex, _("Folder doesn't exist"));
 		g_free (path);
-		return;
+		return FALSE;
 	}
 	g_free (path);
 	g_object_ref (folder);
@@ -3346,221 +3357,79 @@ unsubscribe_folder (MailStub *stub, const gchar *folder_name)
 	/* 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 (mse->account, folder)) {
+	if (!exchange_account_is_favorite_folder (ed->account, folder)) {
 		g_object_unref (folder);
-		mail_stub_return_ok (stub);
-		return;
+		return TRUE;
 	}
 
 	g_object_unref (folder);
 
 	pub_name = strrchr (folder_name, '/');
 	path = g_build_filename ("/favorites", pub_name, NULL);
-	folder = exchange_account_get_folder (mse->account, path);
+	folder = exchange_account_get_folder (ed->account, path);
 	if (!folder) {
-		mail_stub_return_error (stub, _("Folder doesn't exist"));
+		set_exception (ex, _("Folder doesn't exist"));
 		g_free (path);
-		return;
+		return FALSE;
 	}
 	g_object_ref (folder);
 
-	result = exchange_account_remove_favorite (mse->account, 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 (mse->folders_by_name, path + 1);
+		g_hash_table_remove (ed->folders_by_name, path + 1);
 		break;
 
 	case EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED:
-		mail_stub_return_error (stub, _("Permission denied"));
+		set_exception (ex, _("Permission denied"));
 		g_object_unref (folder);
 		g_free (path);
-		return;
+		return FALSE;
 
 	default:
-		mail_stub_return_error (stub, _("Generic error"));
+		set_exception (ex, _("Generic error"));
 		g_object_unref (folder);
 		g_free (path);
-		return;
+		return FALSE;
 
 	}
 
 	g_object_unref (folder);
 	g_free (path);
-	mail_stub_return_ok (stub);
+
+	return TRUE;
 }
 
-static void
-is_subscribed_folder (MailStub *stub, const gchar *folder_name)
+gboolean
+camel_exchange_utils_is_subscribed_folder (CamelService *service,
+					const gchar *folder_name,
+					gboolean *is_subscribed, /* out */
+					CamelException *ex)
 {
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	ExchangeData *ed = get_data_for_service (service);
 	EFolder *folder;
 	gchar *path;
-	guint32 is_subscribed = 0;
+
+	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 (mse->account, path);
+	folder = exchange_account_get_folder (ed->account, path);
 	if (!folder) {
 		g_free (path);
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-				       CAMEL_STUB_ARG_UINT32, is_subscribed,
-				       CAMEL_STUB_ARG_END);
-		mail_stub_return_ok (stub);
-		return;
+		return TRUE;
 	}
 	g_free (path);
 	g_object_ref (folder);
 
-	if (exchange_account_is_favorite_folder (mse->account, folder))
-		is_subscribed = 1;
+	if (exchange_account_is_favorite_folder (ed->account, folder))
+		*is_subscribed = TRUE;
 
 	g_object_unref (folder);
 
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_UINT32, is_subscribed,
-			       CAMEL_STUB_ARG_END);
-	mail_stub_return_ok (stub);
-}
-
-static void
-stub_connect (MailStub *stub, gchar *pwd)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
-	ExchangeAccount *account;
-	ExchangeAccountResult result;
-	E2kContext *ctx;
-	guint32 retval = 1;
-	const gchar *uri;
-	gint mode;
-
-	exchange_component_is_offline (global_exchange_component, &mode);
-
-	account = mse->account;
-	if (mode == ONLINE_MODE)
-		exchange_account_set_online (account);
-	else if (mode == OFFLINE_MODE)
-		exchange_account_set_offline (account);
-
-	ctx = exchange_account_get_context (account);
-	if (!ctx) {
-		ctx = exchange_account_connect (account, pwd, &result);
-	}
-
-	if (!ctx && mode == ONLINE_MODE) {
-		retval = 0;
-		goto end;
-	} else if (mode == OFFLINE_MODE) {
-		goto end;
-	}
-
-	mse->ctx = g_object_ref (ctx);
-
-	mse->mail_submission_uri = exchange_account_get_standard_uri (account, "sendmsg");
-	uri = exchange_account_get_standard_uri (account, "inbox");
-	mse->inbox = exchange_account_get_folder (account, uri);
-	uri = exchange_account_get_standard_uri (account, "deleteditems");
-	mse->deleted_items = exchange_account_get_folder (account, uri);
-	uri = exchange_account_get_standard_uri (account, "sentitems");
-	mse->sent_items = exchange_account_get_folder (account, uri);
-
-	/* Will be used for offline->online transition to initialize things for
-	   the first time */
-
-	g_hash_table_foreach (mse->folders_by_name,
-			      (GHFunc) folder_update_linestatus,
-			      GINT_TO_POINTER (mode));
-end:
-	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
-			       CAMEL_STUB_ARG_UINT32, retval,
-			       CAMEL_STUB_ARG_END);
-
-	mail_stub_return_ok (stub);
-}
-
-#if 0
-static void
-linestatus_listener (ExchangeComponent *component,
-		     gint linestatus,
-		     gpointer data)
-{
-	MailStubExchange *mse = MAIL_STUB_EXCHANGE (data);
-	ExchangeAccount *account = mse->account;
-	const gchar *uri;
-
-	if (linestatus == ONLINE_MODE && mse->ctx == NULL) {
-		mse->ctx = exchange_account_get_context (account);
-		g_object_ref (mse->ctx);
-
-		mse->mail_submission_uri = exchange_account_get_standard_uri (account, "sendmsg");
-		uri = exchange_account_get_standard_uri (account, "inbox");
-		mse->inbox = exchange_account_get_folder (account, uri);
-		uri = exchange_account_get_standard_uri (account, "deleteditems");
-		mse->deleted_items = exchange_account_get_folder (account, uri);
-		g_hash_table_foreach (mse->folders_by_name,
-				      (GHFunc) folder_update_linestatus,
-				      GINT_TO_POINTER (linestatus));
-
-		g_signal_handler_disconnect (G_OBJECT (component),
-					     offline_listener_handler_id);
-		offline_listener_handler_id = 0;
-	} else if (mse->ctx != NULL) {
-		g_signal_handler_disconnect (G_OBJECT (component),
-					     offline_listener_handler_id);
-		offline_listener_handler_id = 0;
-	}
-}
-
-#endif
-
-static void
-folder_update_linestatus (gpointer key, gpointer value, gpointer data)
-{
-	MailStubExchangeFolder *mfld = (MailStubExchangeFolder *) value;
-	MailStub *stub = MAIL_STUB (mfld->mse);
-	gint linestatus = GPOINTER_TO_INT (data);
-	guint32 readonly;
-
-	if (linestatus == ONLINE_MODE) {
-		get_folder_online (mfld, TRUE);
-		readonly = (mfld->access & (MAPI_ACCESS_MODIFY | MAPI_ACCESS_CREATE_CONTENTS)) ? 0 : 1;
-		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_FOLDER_SET_READONLY,
-				       CAMEL_STUB_ARG_FOLDER, mfld->name,
-				       CAMEL_STUB_ARG_UINT32, readonly,
-				       CAMEL_STUB_ARG_END);
-	}
-	else {
-		/* FIXME: need any undo for offline */ ;
-	}
-}
-
-/**
- * mail_stub_exchange_new:
- * @account: the #ExchangeAccount this stub is for
- * @cmd_fd: command socket file descriptor
- * @status_fd: status socket file descriptor
- *
- * Creates a new #MailStubExchange for @account, communicating over
- * @cmd_fd and @status_fd.
- *
- * Return value: the new stub
- **/
-MailStub *
-mail_stub_exchange_new (ExchangeAccount *account, gint cmd_fd, gint status_fd)
-{
-	MailStubExchange *mse;
-	MailStub *stub;
-
-	stub = g_object_new (MAIL_TYPE_STUB_EXCHANGE, NULL);
-	g_object_ref (stub);
-	mail_stub_construct (stub, cmd_fd, status_fd);
-
-	mse = (MailStubExchange *)stub;
-	mse->account = account;
-
-	/* offline_listener_handler_id = g_signal_connect (G_OBJECT (global_exchange_component),
-							"linestatus-changed",
-							G_CALLBACK (linestatus_listener), mse); */
-	return stub;
+	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/mail/mail-utils.c b/camel/mail-utils.c
similarity index 97%
rename from mail/mail-utils.c
rename to camel/mail-utils.c
index 26e81da..4505378 100644
--- a/mail/mail-utils.c
+++ b/camel/mail-utils.c
@@ -22,7 +22,6 @@
 #endif
 
 #include "mail-utils.h"
-#include "mail-stub.h"
 #include <e2k-propnames.h>
 #include <e2k-utils.h>
 #include <mapi.h>
@@ -31,6 +30,7 @@
 #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>
@@ -123,32 +123,32 @@ mail_util_props_to_camel_flags (E2kProperties *props, gboolean obey_read_flag)
 
 	prop = e2k_properties_get_prop (props, E2K_PR_HTTPMAIL_READ);
 	if ((prop && atoi (prop)) || !obey_read_flag)
-		flags |= MAIL_STUB_MESSAGE_SEEN;
+		flags |= CAMEL_MESSAGE_SEEN;
 
 	prop = e2k_properties_get_prop (props, E2K_PR_HTTPMAIL_HAS_ATTACHMENT);
 	if (prop && atoi (prop))
-		flags |= MAIL_STUB_MESSAGE_ATTACHMENTS;
+		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 |= MAIL_STUB_MESSAGE_ANSWERED;
+			flags |= CAMEL_MESSAGE_ANSWERED;
 		else if (val == MAPI_ACTION_FLAG_REPLIED_TO_ALL) {
-			flags |= (MAIL_STUB_MESSAGE_ANSWERED |
-				  MAIL_STUB_MESSAGE_ANSWERED_ALL);
+			flags |= (CAMEL_MESSAGE_ANSWERED |
+				  CAMEL_MESSAGE_ANSWERED_ALL);
 		}
 	}
 
 	prop = e2k_properties_get_prop (props, PR_DELEGATED_BY_RULE);
 	if (prop && atoi (prop))
-		flags |= MAIL_STUB_MESSAGE_DELEGATED;
+		flags |= EXMAIL_DELEGATED;
 
 	prop = e2k_properties_get_prop (props, PR_IMPORTANCE);
 	if (prop) {
 		val = atoi (prop);
 		if (val == MAPI_IMPORTANCE_HIGH)
-			flags |= MAIL_STUB_MESSAGE_FLAGGED;
+			flags |= CAMEL_MESSAGE_FLAGGED;
 	}
 
 	return flags;
diff --git a/mail/mail-utils.h b/camel/mail-utils.h
similarity index 90%
rename from mail/mail-utils.h
rename to camel/mail-utils.h
index 15fc1b2..588485f 100644
--- a/mail/mail-utils.h
+++ b/camel/mail-utils.h
@@ -4,8 +4,12 @@
 #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 {
diff --git a/configure.ac b/configure.ac
index 9258041..e7003c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ AC_PREREQ(2.52)
 m4_define([eex_version], [2.29.1])
 
 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
@@ -375,10 +375,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/po/POTFILES.in b/po/POTFILES.in
index 4095e2d..d9a9de1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,14 +10,9 @@ camel/camel-exchange-journal.c
 camel/camel-exchange-provider.c
 camel/camel-exchange-store.c
 camel/camel-exchange-transport.c
-camel/camel-stub.c
-mail/mail-stub-exchange.c
-storage/GNOME_Evolution_Exchange_Storage.server.in.in
-storage/exchange-autoconfig-wizard.c
-storage/exchange-component.c
-storage/exchange-config-listener.c
-storage/exchange-migrate.c
-storage/exchange-storage.c
-storage/main.c
-storage/ximian-connector-setup.c
-storage/ximian-connector.xml
+camel/camel-exchange-utils.c
+camel/mail-utils.c
+tools/exchange-autoconfig-wizard.c
+tools/exchange-share-config-listener.c
+tools/ximian-connector-setup.c
+tools/ximian-connector.xml
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/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/storage/connector-mini.png b/tools/connector-mini.png
similarity index 100%
rename from storage/connector-mini.png
rename to tools/connector-mini.png
diff --git a/storage/connector.png b/tools/connector.png
similarity index 100%
rename from storage/connector.png
rename to tools/connector.png
diff --git a/storage/exchange-autoconfig-wizard.c b/tools/exchange-autoconfig-wizard.c
similarity index 99%
rename from storage/exchange-autoconfig-wizard.c
rename to tools/exchange-autoconfig-wizard.c
index 43cb98b..4929d8c 100644
--- a/storage/exchange-autoconfig-wizard.c
+++ b/tools/exchange-autoconfig-wizard.c
@@ -37,8 +37,6 @@
 #include <gconf/gconf-client.h>
 #include <gtk/gtk.h>
 
-#include "exchange-storage.h"
-
 #ifdef G_OS_WIN32
 
 #undef CONNECTOR_IMAGESDIR
diff --git a/storage/exchange-autoconfig-wizard.h b/tools/exchange-autoconfig-wizard.h
similarity index 100%
rename from storage/exchange-autoconfig-wizard.h
rename to tools/exchange-autoconfig-wizard.h
diff --git a/storage/exchange-delegates-48.png b/tools/exchange-delegates-48.png
similarity index 100%
rename from storage/exchange-delegates-48.png
rename to tools/exchange-delegates-48.png
diff --git a/storage/exchange-oof-48.png b/tools/exchange-oof-48.png
similarity index 100%
rename from storage/exchange-oof-48.png
rename to tools/exchange-oof-48.png
diff --git a/storage/exchange-config-listener.c b/tools/exchange-share-config-listener.c
similarity index 80%
rename from storage/exchange-config-listener.c
rename to tools/exchange-share-config-listener.c
index 2c336ac..499841d 100644
--- a/storage/exchange-config-listener.c
+++ b/tools/exchange-share-config-listener.c
@@ -17,7 +17,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-/* ExchangeConfigListener: a class that listens to the config database
+/* 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.
  */
@@ -48,13 +48,10 @@
 
 #include <e-util/e-dialog-utils.h>
 
-#include "mail-stub-listener.h"
+#include "exchange-share-config-listener.h"
 
-#include "exchange-config-listener.h"
-
-struct _ExchangeConfigListenerPrivate {
+struct _ExchangeShareConfigListenerPrivate {
 	GConfClient *gconf;
-	guint idle_id;
 
 	gchar *configured_uri, *configured_name;
 	EAccount *configured_account;
@@ -81,6 +78,8 @@ static guint signals [LAST_SIGNAL] = { 0 };
 #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);
@@ -117,7 +116,7 @@ class_init (GObjectClass *object_class)
 		g_signal_new ("exchange_account_created",
 			      G_OBJECT_CLASS_TYPE (object_class),
 			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_created),
+			      G_STRUCT_OFFSET (ExchangeShareConfigListenerClass, exchange_account_created),
 			      NULL, NULL,
 			      g_cclosure_marshal_VOID__POINTER,
 			      G_TYPE_NONE, 1,
@@ -126,7 +125,7 @@ class_init (GObjectClass *object_class)
 		g_signal_new ("exchange_account_removed",
 			      G_OBJECT_CLASS_TYPE (object_class),
 			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ExchangeConfigListenerClass, exchange_account_removed),
+			      G_STRUCT_OFFSET (ExchangeShareConfigListenerClass, exchange_account_removed),
 			      NULL, NULL,
 			      g_cclosure_marshal_VOID__POINTER,
 			      G_TYPE_NONE, 1,
@@ -136,22 +135,17 @@ class_init (GObjectClass *object_class)
 static void
 init (GObject *object)
 {
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (object);
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
 
-	config_listener->priv = g_new0 (ExchangeConfigListenerPrivate, 1);
+	config_listener->priv = g_new0 (ExchangeShareConfigListenerPrivate, 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;
-	}
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
 
 	if (config_listener->priv->gconf) {
 		g_object_unref (config_listener->priv->gconf);
@@ -164,8 +158,8 @@ dispose (GObject *object)
 static void
 finalize (GObject *object)
 {
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (object);
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (object);
 
 	g_free (config_listener->priv->configured_name);
 	g_free (config_listener->priv->configured_uri);
@@ -174,7 +168,7 @@ finalize (GObject *object)
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-E2K_MAKE_TYPE (exchange_config_listener, ExchangeConfigListener, class_init, init, PARENT_TYPE)
+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)
@@ -358,7 +352,7 @@ migrate_account_esource (EAccount *account,
 }
 
 void
-exchange_config_listener_migrate_esources (ExchangeConfigListener *config_listener)
+exchange_share_config_listener_migrate_esources (ExchangeShareConfigListener *config_listener)
 {
 	EAccount *account;
 
@@ -374,13 +368,13 @@ exchange_config_listener_migrate_esources (ExchangeConfigListener *config_listen
 static void
 account_added (EAccountList *account_list, EAccount *account)
 {
-	ExchangeConfigListener *config_listener;
+	ExchangeShareConfigListener *config_listener;
 	ExchangeAccount *exchange_account;
 
 	if (!is_active_exchange_account (account))
 		return;
 
-	config_listener = EXCHANGE_CONFIG_LISTENER (account_list);
+	config_listener = EXCHANGE_SHARE_CONFIG_LISTENER (account_list);
 	if (config_listener->priv->configured_account) {
 		/* Multiple accounts configured. */
 		return;
@@ -404,7 +398,7 @@ account_added (EAccountList *account_list, EAccount *account)
 
 	g_signal_emit (config_listener, signals[EXCHANGE_ACCOUNT_CREATED], 0,
 		       exchange_account);
-	exchange_config_listener_migrate_esources (config_listener);
+	exchange_share_config_listener_migrate_esources (config_listener);
 }
 
 struct account_update_data {
@@ -417,7 +411,7 @@ 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)
+	if (!EXCHANGE_SHARE_CONFIG_LISTENER (aud->account_list)->priv->configured_account)
 		account_added (aud->account_list, aud->account);
 
 	g_object_unref (aud->account_list);
@@ -485,9 +479,9 @@ end:
 static void
 account_changed (EAccountList *account_list, EAccount *account)
 {
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (account_list);
-	ExchangeConfigListenerPrivate *priv = config_listener->priv;
+	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))
@@ -569,9 +563,9 @@ account_changed (EAccountList *account_list, EAccount *account)
 static void
 account_removed (EAccountList *account_list, EAccount *account)
 {
-	ExchangeConfigListener *config_listener =
-		EXCHANGE_CONFIG_LISTENER (account_list);
-	ExchangeConfigListenerPrivate *priv = config_listener->priv;
+	ExchangeShareConfigListener *config_listener =
+		EXCHANGE_SHARE_CONFIG_LISTENER (account_list);
+	ExchangeShareConfigListenerPrivate *priv = config_listener->priv;
 
 	if (account != priv->configured_account)
 		return;
@@ -594,21 +588,10 @@ account_removed (EAccountList *account_list, EAccount *account)
 	}
 }
 
-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:
+ * exchange_share_config_listener_new:
  *
- * This creates and returns a new #ExchangeConfigListener, which
+ * 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
@@ -621,24 +604,24 @@ idle_construct (gpointer data)
  *
  * Return value: the new config listener.
  **/
-ExchangeConfigListener *
-exchange_config_listener_new (void)
+ExchangeShareConfigListener *
+exchange_share_config_listener_new (void)
 {
-	ExchangeConfigListener *config_listener;
+	ExchangeShareConfigListener *config_listener;
 
-	config_listener = g_object_new (EXCHANGE_TYPE_CONFIG_LISTENER, NULL);
+	config_listener = g_object_new (EXCHANGE_TYPE_SHARE_CONFIG_LISTENER, NULL);
 	config_listener->priv->gconf = gconf_client_get_default ();
 
-	config_listener->priv->idle_id =
-		g_idle_add (idle_construct, config_listener);
+	e_account_list_construct (E_ACCOUNT_LIST (config_listener),
+				  config_listener->priv->gconf);
 
 	return config_listener;
 }
 
 GSList *
-exchange_config_listener_get_accounts (ExchangeConfigListener *config_listener)
+exchange_share_config_listener_get_accounts (ExchangeShareConfigListener *config_listener)
 {
-	g_return_val_if_fail (EXCHANGE_IS_CONFIG_LISTENER (config_listener), NULL);
+	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);
@@ -690,3 +673,111 @@ exchange_camel_urls_is_equal (const gchar *url1, const gchar *url2)
 	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/storage/migr-test.c b/tools/migr-test.c
similarity index 100%
rename from storage/migr-test.c
rename to tools/migr-test.c
diff --git a/storage/ximian-connector-setup.c b/tools/ximian-connector-setup.c
similarity index 100%
rename from storage/ximian-connector-setup.c
rename to tools/ximian-connector-setup.c
diff --git a/storage/ximian-connector.xml b/tools/ximian-connector.xml
similarity index 100%
rename from storage/ximian-connector.xml
rename to tools/ximian-connector.xml



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]