Index: camel/camel-stub-constants.h
===================================================================
--- camel/camel-stub-constants.h	(revision 1359)
+++ camel/camel-stub-constants.h	(working copy)
@@ -32,7 +32,10 @@
 	CAMEL_STUB_CMD_RENAME_FOLDER,
 	CAMEL_STUB_CMD_SUBSCRIBE_FOLDER,
 	CAMEL_STUB_CMD_UNSUBSCRIBE_FOLDER,
-	CAMEL_STUB_CMD_IS_SUBSCRIBED_FOLDER
+	CAMEL_STUB_CMD_IS_SUBSCRIBED_FOLDER,
+	CAMEL_STUB_CMD_PASSWORD_PRESENTED,
+	CAMEL_STUB_CMD_CERTIFICATE_PRESENTED,
+	CAMEL_STUB_CMD_DATA_SIGNED
 } CamelStubCommand;
 
 typedef enum {
@@ -44,7 +47,8 @@
 	CAMEL_STUB_ARG_BYTEARRAY,
 	CAMEL_STUB_ARG_STRINGARRAY,
 	CAMEL_STUB_ARG_FOLDER,
-	CAMEL_STUB_ARG_UINT32ARRAY
+	CAMEL_STUB_ARG_UINT32ARRAY,
+	CAMEL_STUB_ARG_BYTEARRAY_ARRAY
 } CamelStubArgType;
 
 typedef enum {
@@ -66,7 +70,10 @@
 	CAMEL_STUB_RETVAL_FOLDER_CREATED,
 	CAMEL_STUB_RETVAL_FOLDER_DELETED,
 	CAMEL_STUB_RETVAL_FOLDER_RENAMED,
-	CAMEL_STUB_RETVAL_FOLDER_SET_READONLY
+	CAMEL_STUB_RETVAL_FOLDER_SET_READONLY,
+	CAMEL_STUB_RETVAL_PASSWORD_REQUIRED,
+	CAMEL_STUB_RETVAL_CERTIFICATE_REQUESTED,
+	CAMEL_STUB_RETVAL_SIGN_DATA
 } CamelStubRetval;
 
 typedef enum {
Index: camel/camel-stub-marshal.c
===================================================================
--- camel/camel-stub-marshal.c	(revision 1359)
+++ camel/camel-stub-marshal.c	(working copy)
@@ -88,8 +88,8 @@
 {
 	size_t nread = 0;
 	ssize_t n;
-	
-	do {
+
+	while (marshal->fd != -1 && nread < len) {
 		if ((n = camel_read (marshal->fd, buf + nread, len - nread)) <= 0) {
 			if (errno != ETIMEDOUT)
 				break;
@@ -97,7 +97,7 @@
 				n = 0;
 		}
 		nread += n;
-	} while (nread < len);
+	}
 	
 	if (nread < len) {
 		close (marshal->fd);
Index: camel/Makefile.am
===================================================================
--- camel/Makefile.am	(revision 1359)
+++ camel/Makefile.am	(working copy)
@@ -9,6 +9,7 @@
 	$(CAMEL_CFLAGS)				\
 	$(SHELL_CFLAGS)				\
 	$(LIBEXCHANGE_CFLAGS)			\
+	$(EXCHANGE_STORAGE_CFLAGS)		\
 	-DCONNECTOR_LOCALEDIR=\"$(localedir)\"	\
 	-DG_LOG_DOMAIN=\"camel-exchange-provider\"	
 
Index: camel/camel-exchange-store.c
===================================================================
--- camel/camel-exchange-store.c	(revision 1359)
+++ camel/camel-exchange-store.c	(working copy)
@@ -27,6 +27,10 @@
 
 #include <glib/gi18n-lib.h>
 
+#ifdef HAVE_GNOME_CERTAUTH
+#include <gnome-certauth/gca-nss.h>
+#endif /* HAVE_GNOME_CERTAUTH */
+
 #include "camel-exchange-store.h"
 #include "camel-exchange-folder.h"
 #include "camel-exchange-summary.h"
@@ -416,6 +420,7 @@
 		return TRUE;
 	}
 
+#if 0
 	if (online_mode) {
 		camel_exchange_get_password (service, ex);
 		if (camel_exception_is_set (ex)) {
@@ -424,6 +429,7 @@
 		}
 		password = service->url->passwd;
 	}
+#endif
 
 	/* Initialize the stub connection */
 	if (!camel_stub_send (exch->stub, NULL, CAMEL_STUB_CMD_CONNECT,
@@ -843,6 +849,23 @@
 			 CAMEL_STUB_ARG_END);
 }
 
+#ifdef HAVE_GNOME_CERTAUTH
+static gnutls_datum_t *
+data_to_datum (gnutls_datum_t *datum, const GByteArray *data)
+{
+	datum->size = data->len;
+	datum->data = data->data;
+	return datum;
+}
+static GByteArray *
+datum_to_data (GByteArray *data, const gnutls_datum_t *datum)
+{
+	data->len = datum->size;
+	data->data = datum->data;
+	return data;
+}
+#endif
+
 static void
 stub_notification (CamelObject *object, gpointer event_data, gpointer user_data)
 {
@@ -1120,6 +1143,122 @@
 		break;
 	}
 
+	case CAMEL_STUB_RETVAL_PASSWORD_REQUIRED:
+	{
+		CamelService *service = CAMEL_SERVICE (exch);
+		CamelException ex;
+		char *password = NULL;
+
+		camel_exception_init (&ex);
+		camel_exchange_get_password (service, &ex);
+		if (camel_exception_is_set (&ex)) {
+			camel_exception_clear (&ex);
+			break;
+		} else {
+			password = service->url->passwd;
+		}
+
+		camel_stub_send_oneway (stub, CAMEL_STUB_CMD_PASSWORD_PRESENTED,
+					CAMEL_STUB_ARG_STRING, password,
+					CAMEL_STUB_ARG_END);
+	}
+
+#ifdef HAVE_GNOME_CERTAUTH
+	case CAMEL_STUB_RETVAL_CERTIFICATE_REQUESTED:
+	{
+		gnutls_datum_t *req_ca_rdn_der = NULL;
+		guint32 nreqs;
+
+		gnutls_datum_t *cert_der_ret = NULL;
+		int cert_der_ret_length = 0;
+		GPtrArray *gcert_der = NULL;
+
+		GByteArray *tmp;
+		int i;
+		int status;
+
+		if (camel_stub_marshal_decode_uint32 (stub->status, &nreqs) == -1) {
+			nreqs = 0;
+			goto i_has_an_error;
+		}
+
+		req_ca_rdn_der = g_new0 (gnutls_datum_t, nreqs);
+		for (i = 0; i < nreqs && status != -1; i++) {
+			status = camel_stub_marshal_decode_bytes (stub->status, &tmp);
+			if (status != -1) {
+				data_to_datum (&req_ca_rdn_der[i], tmp);
+				g_byte_array_free (tmp, FALSE);
+			}
+		}
+		if (status == -1) {
+			/* only clean up part-way */
+			nreqs = i;
+			goto i_has_an_error;
+		}
+
+		gca_nss_request_certificate (req_ca_rdn_der, nreqs,
+					     &cert_der_ret, &cert_der_ret_length);
+
+		/* this is lame... */
+		gcert_der = g_ptr_array_sized_new (cert_der_ret_length);
+		g_ptr_array_set_size (gcert_der, cert_der_ret_length);
+		for (i = 0; i < cert_der_ret_length; i++) {
+			tmp = g_byte_array_new ();
+			datum_to_data (tmp, &cert_der_ret[i]);
+			g_ptr_array_index (gcert_der, i) = tmp;
+		}
+
+		/* i_has_an_error: */
+		camel_stub_send_oneway (stub, CAMEL_STUB_CMD_CERTIFICATE_PRESENTED,
+					CAMEL_STUB_ARG_BYTEARRAY_ARRAY, gcert_der,
+					CAMEL_STUB_ARG_END);
+
+		for (i = 0; i < cert_der_ret_length; i++) {
+			g_byte_array_free (g_ptr_array_index (gcert_der, i), TRUE);
+		}
+		g_free (cert_der_ret);
+		g_ptr_array_free (gcert_der, TRUE);
+
+	i_has_an_error:
+		for (i = 0; i < nreqs; i++) {
+			g_free (req_ca_rdn_der[i].data);
+		}
+		g_free (req_ca_rdn_der);
+
+		break;
+	}
+
+	case CAMEL_STUB_RETVAL_SIGN_DATA:
+	{
+		GByteArray *cert = NULL;
+		gnutls_datum_t cert_datum;
+		GByteArray *hash = NULL;
+		gnutls_datum_t hash_datum;
+		GByteArray signature;
+		gnutls_datum_t signature_datum;
+
+		if (camel_stub_marshal_decode_bytes (stub->status, &cert) == -1 ||
+		    camel_stub_marshal_decode_bytes (stub->status, &hash) == -1) {
+			goto i_has_an_error_sign;
+		}
+
+		gca_nss_sign_data (data_to_datum (&cert_datum, cert),
+				   data_to_datum (&hash_datum, hash),
+				   data_to_datum (&signature_datum, &signature));
+		camel_stub_send_oneway (stub, CAMEL_STUB_CMD_DATA_SIGNED,
+					CAMEL_STUB_ARG_BYTEARRAY, datum_to_data (&signature, &signature_datum),
+					CAMEL_STUB_ARG_END);
+
+		g_free (signature.data);
+
+	i_has_an_error_sign:
+		g_byte_array_free (cert, TRUE);
+		g_byte_array_free (hash, TRUE);
+
+		break;
+	}
+#endif
+
 	default:
 		g_assert_not_reached ();
 		break;
Index: camel/camel-stub.c
===================================================================
--- camel/camel-stub.c	(revision 1359)
+++ camel/camel-stub.c	(working copy)
@@ -316,6 +316,18 @@
 				camel_stub_marshal_encode_uint32 (stub->cmd, g_array_index (arr, guint32, i));
 			break;
 		}		
+
+		case CAMEL_STUB_ARG_BYTEARRAY_ARRAY:
+		{
+			GPtrArray *arr = va_arg (ap, GPtrArray *);
+			int i;
+
+			camel_stub_marshal_encode_uint32 (stub->cmd, arr->len);
+			for (i = 0; i < arr->len; i++) {
+				camel_stub_marshal_encode_bytes (stub->cmd, g_ptr_array_index (arr, i));
+			}
+			break;
+		}
 		
 		default:
 			g_assert_not_reached ();
Index: mail/mail-stub-exchange.h
===================================================================
--- mail/mail-stub-exchange.h	(revision 1359)
+++ mail/mail-stub-exchange.h	(working copy)
@@ -20,7 +20,7 @@
 
 typedef struct _MailStubExchange        MailStubExchange;
 typedef struct _MailStubExchangeClass   MailStubExchangeClass;
-
+typedef struct _MailStubExchangeCreds   MailStubExchangeCreds;
 struct _MailStubExchange {
 	MailStub parent;
 
@@ -32,6 +32,7 @@
 
 	guint new_folder_id, removed_folder_id;
 	const char *ignore_new_folder, *ignore_removed_folder;
+	MailStubExchangeCreds *creds;
 };
 
 struct _MailStubExchangeClass {
Index: mail/mail-stub.h
===================================================================
--- mail/mail-stub.h	(revision 1359)
+++ mail/mail-stub.h	(working copy)
@@ -8,6 +8,7 @@
 #include <glib-object.h>
 #include "camel-stub-constants.h"
 #include "camel-stub-marshal.h"
+#include <gnutls/gnutls.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -72,6 +73,10 @@
 	void (*subscribe_folder)   (MailStub *, const char *folder_name);
 	void (*unsubscribe_folder)   (MailStub *, const char *folder_name);
 	void (*is_subscribed_folder)   (MailStub *, const char *folder_name);
+
+	void (*certificate_presented) (MailStub *, const gnutls_datum_t *cert_der_ret, int ncerts);
+	void (*data_signed) (MailStub *, const gnutls_datum_t *signature);
+	void (*password_presented) (MailStub *, const char *password);
 };
 
 GType             mail_stub_get_type        (void);
Index: mail/mail-stub-exchange.c
===================================================================
--- mail/mail-stub-exchange.c	(revision 1359)
+++ mail/mail-stub-exchange.c	(working copy)
@@ -43,8 +43,15 @@
 #include <exchange-hierarchy.h>
 #include <mapi.h>
 
-#define d(x)
+#define TRACE(s, ...) d(fprintf (stderr, "%d:%s:%s():%d "s"\n", getpid(), __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__))
+#define TRACEMSG(s) TRACE("%s", (s))
+#define ENTER TRACEMSG("ENTER")
+#define EXIT TRACEMSG("EXIT")
+#define HASLOCK TRACEMSG("HAS LOCK")
+#define ALREADYLOCKED TRACEMSG("ALREADY LOCKED")
 
+#define d(x) x
+
 #define PARENT_TYPE MAIL_TYPE_STUB
 static MailStubClass *parent_class = NULL;
 
@@ -87,6 +94,21 @@
 	guint sync_deletion_timeout;
 } MailStubExchangeFolder;
 
+struct _MailStubExchangeCreds {
+	E2kCreds creds;
+	GMutex *mutex;
+	GMutex *cond_mutex;
+	GCond *cond;
+	CamelStubCommand expected_cmd;
+	gboolean returned;
+	MailStubExchange *mse;
+	int mode;
+	char *pwd;
+	gnutls_datum_t *cert_der_ret;
+	int cert_der_ret_length;
+	gnutls_datum_t *signature;
+};
+
 static void dispose (GObject *);
 
 static void stub_connect (MailStub *stub, char *pwd);
@@ -95,8 +117,11 @@
 static void get_trash_name (MailStub *stub);
 static void sync_folder (MailStub *stub, const char *folder_name);
 static void refresh_folder (MailStub *stub, const char *folder_name);
+typedef void (*FolderRefreshedFunc) (MailStub *stub, MailStubExchangeFolder *mfld,
+				     gpointer user_data);
 static void refresh_folder_internal (MailStub *stub, MailStubExchangeFolder *mfld,
-				     gboolean background);
+				     gboolean background, 
+				     FolderRefreshedFunc func, gpointer user_data);
 static void sync_deletions (MailStubExchange *mse, MailStubExchangeFolder *mfld);
 static void expunge_uids (MailStub *stub, const char *folder_name, GPtrArray *uids);
 static void append_message (MailStub *stub, const char *folder_name, guint32 flags,
@@ -134,6 +159,10 @@
 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 certificate_presented (MailStub *, const gnutls_datum_t *, int);
+static void data_signed (MailStub *, const gnutls_datum_t *);
+static void password_presented (MailStub *, const char *);
+
 static void
 class_init (GObjectClass *object_class)
 {
@@ -164,6 +193,9 @@
 	stub_class->subscribe_folder = subscribe_folder;
 	stub_class->unsubscribe_folder = unsubscribe_folder;
 	stub_class->is_subscribed_folder = is_subscribed_folder;
+	stub_class->certificate_presented = certificate_presented;
+	stub_class->data_signed = data_signed;
+	stub_class->password_presented = password_presented;
 }
 
 static void
@@ -232,6 +264,18 @@
 		mse->removed_folder_id = 0;
 	}
 
+	if (mse->creds) {
+		exchange_account_remove_creds (mse->account, &mse->creds->creds);
+		g_object_unref (mse->account);
+
+		g_mutex_free (mse->creds->mutex);
+		g_mutex_free (mse->creds->cond_mutex);
+		g_cond_free (mse->creds->cond);
+		g_free (mse->creds->pwd);
+		g_free (mse->creds);
+		mse->creds = NULL;
+	}
+
 /*	if (g_signal_handler_is_connected (G_OBJECT (global_exchange_component),
 					   offline_listener_handler_id)) {
 		g_signal_handler_disconnect (G_OBJECT (global_exchange_component),
@@ -462,7 +506,7 @@
 	time_t now;
 
 	if (type == E2K_CONTEXT_OBJECT_ADDED)
-		refresh_folder_internal (MAIL_STUB (mfld->mse), mfld, TRUE);
+		refresh_folder_internal (MAIL_STUB (mfld->mse), mfld, TRUE, NULL, NULL);
 	else {
 		now = time (NULL);
 
@@ -522,7 +566,7 @@
 	MailStubExchangeFolder *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 (MAIL_STUB (mfld->mse), mfld, TRUE, NULL, NULL);
 }
 
 static void
@@ -1050,10 +1094,21 @@
 };
 static const int num_new_message_props = sizeof (new_message_props) / sizeof (new_message_props[0]);
 
-static void
-refresh_folder_internal (MailStub *stub, MailStubExchangeFolder *mfld,
-			 gboolean background)
+typedef struct {
+	MailStub *stub;
+	MailStubExchangeFolder *mfld;
+	gboolean background;
+	FolderRefreshedFunc func;
+	gpointer user_data;
+} RefreshFolderData;
+
+static gpointer
+refresh_folder_thread (gpointer user_data)
 {
+	RefreshFolderData *data = user_data;
+	MailStub *stub = data->stub;
+	MailStubExchangeFolder *mfld = data->mfld;;
+	gboolean background = data->background;
 	E2kRestriction *rn;
 	GArray *messages;
 	GHashTable *mapi_message_hash;
@@ -1068,8 +1123,6 @@
 	gpointer key, value;
 	MailStubExchangeMessage *mmsg;
 
-	g_object_ref (stub);
-
 	exchange_component_is_offline (global_exchange_component, &mode);
 	if (mode == OFFLINE_MODE) {
 		if (background)
@@ -1077,8 +1130,13 @@
 		else
 			mail_stub_return_ok (stub);
 
+		if (data->func) {
+			data->func (stub, mfld, data->user_data);
+		}
+
 		g_object_unref (stub); /* Is this needed ? */
-		return;
+		g_free (data);
+		return NULL;
 	}
 
 	messages = g_array_new (FALSE, FALSE, sizeof (struct refresh_message));
@@ -1301,10 +1359,39 @@
 	g_hash_table_destroy (mapi_message_hash);
 	g_ptr_array_free (mapi_hrefs, TRUE);
 
+	if (data->func) {
+		data->func (stub, mfld, data->user_data);
+	}
+
 	g_object_unref (stub);
+	g_free (data);
+	return NULL;
 }
 
 static void
+refresh_folder_internal (MailStub *stub, MailStubExchangeFolder *mfld,
+			 gboolean background,
+			 FolderRefreshedFunc func, gpointer user_data)
+{
+	RefreshFolderData *data;
+
+	data = g_new0 (RefreshFolderData, 1);
+	data->stub = g_object_ref (stub);
+	data->mfld = mfld;
+	data->background = background;
+	data->func = func;
+	data->user_data = user_data;
+
+	g_thread_create (refresh_folder_thread, data, FALSE, NULL);
+}
+
+static void
+folder_refreshed (MailStub *stub, MailStubExchangeFolder *mfld, gpointer user_data)
+{
+	sync_deletions (MAIL_STUB_EXCHANGE (stub), mfld);
+}
+
+static void
 refresh_folder (MailStub *stub, const char *folder_name)
 {
 	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
@@ -1314,8 +1401,7 @@
 	if (!mfld)
 		return;
 
-	refresh_folder_internal (stub, mfld, FALSE);
-	sync_deletions (mse, mfld);
+	refresh_folder_internal (stub, mfld, FALSE, folder_refreshed, NULL);
 }
 
 static void
@@ -2295,7 +2381,7 @@
 	exchange_account_is_offline (mse->account, &mode);
 	if (!subscribed) {
 		ExchangeAccountResult result = -1;
-		d(g_print ("%s(%d):%s: NOT SUBSCRIBED top = [%s]\n", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__, top));
+		d(g_print ("%s(%d):%s: NOT SUBSCRIBED top = [%s]\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, top));
 		if (!toplen)
 			result = exchange_account_open_folder (mse->account, "/public");
 		if (result ==  EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST) {
@@ -2303,11 +2389,11 @@
 			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));
+			d(g_print ("%s(%d):%s: NOT SUBSCRIBED - open_folder returned = [%d]\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, result));
 	}
 
 	if (!recursive && toplen) {
-		d(g_print ("%s(%d):%s: NOT RECURSIVE and toplen top = [%s]\n", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__, top));
+		d(g_print ("%s(%d):%s: NOT RECURSIVE and toplen top = [%s]\n", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, top));
 		full_path = g_strdup_printf ("/%s", top);
 		folders = exchange_account_get_folder_tree (mse->account, full_path);
 			/*
@@ -2323,7 +2409,7 @@
 		g_free (full_path);
 	} else {
 		d(g_print ("%s(%d):%s calling exchange_account_get_folders \n", __FILE__, __LINE__,
-					   __GNUC_PRETTY_FUNCTION__));
+					   G_GNUC_PRETTY_FUNCTION));
 		folders = exchange_account_get_folders (mse->account);
 	}
 
@@ -2406,7 +2492,7 @@
 				folder_flags |= CAMEL_STUB_FOLDER_SYSTEM|CAMEL_STUB_FOLDER_TYPE_INBOX;
 
 			if (!e_folder_exchange_get_has_subfolders (folder)) {
-				d(printf ("%s:%d:%s - %s has no subfolders", __FILE__, __LINE__, __GNUC_PRETTY_FUNCTION__,
+				d(printf ("%s:%d:%s - %s has no subfolders", __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,
 					  name));
 				folder_flags |= CAMEL_STUB_FOLDER_NOCHILDREN;
 			}
@@ -2812,15 +2898,337 @@
 	mail_stub_return_ok (stub);
 }
 
+static char *
+stub_connect_http_auth_method (E2kCreds *ecreds)
+{
+	MailStubExchangeCreds *creds = (MailStubExchangeCreds *)ecreds;
+	return exchange_account_get_authtype (creds->mse->account);
+}
+
 static void
+password_presented (MailStub *stub, const char *password)
+{
+	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	MailStubExchangeCreds *creds = mse->creds;
+
+	ENTER;
+
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	if (creds->expected_cmd == CAMEL_STUB_CMD_PASSWORD_PRESENTED) {
+		creds->pwd = g_strdup (password);
+
+		creds->returned = TRUE;
+		g_cond_signal (creds->cond);
+	} else {
+		fprintf (stderr, "Got Spurious PASSWORD_PRESENTED; ignoring\n");
+	}
+
+	g_mutex_unlock (creds->cond_mutex);
+
+	EXIT;
+}
+
+static void
+stub_connect_http_authenticate (E2kCreds *ecreds,
+				const char *auth_type, const char *auth_realm,
+				char **username, char **password)
+{
+	MailStubExchangeCreds *creds = (MailStubExchangeCreds *)ecreds;
+	MailStubExchange *mse;
+	MailStub *stub;
+
+	ENTER;
+
+	g_mutex_lock (creds->mutex);
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	mse = creds->mse;
+	g_object_ref (mse);
+
+	creds->expected_cmd = CAMEL_STUB_CMD_PASSWORD_PRESENTED;
+
+	if (!creds->pwd) {
+		stub = MAIL_STUB (mse);
+		*username = exchange_account_get_username (mse->account);
+		mail_stub_return_data (stub, CAMEL_STUB_RETVAL_PASSWORD_REQUIRED,
+				       CAMEL_STUB_ARG_END);
+		mail_stub_push_changes (stub);
+	
+		while (!creds->returned) {
+			g_cond_wait (creds->cond, creds->cond_mutex);
+		}
+		creds->returned = FALSE;
+	}
+
+	*password = creds->pwd;
+
+	creds->expected_cmd = -1;
+
+	g_object_unref (mse);
+	g_mutex_unlock (creds->cond_mutex);
+	g_mutex_unlock (creds->mutex);
+
+	EXIT;
+}
+
+#ifdef HAVE_GNOME_CERTAUTH
+static gnutls_datum_t *
+data_to_datum (gnutls_datum_t *datum, const GByteArray *data)
+{
+	datum->size = data->len;
+	datum->data = data->data;
+	return datum;
+}
+static GByteArray *
+datum_to_data (GByteArray *data, const gnutls_datum_t *datum)
+{
+	data->len = datum->size;
+	data->data = datum->data;
+	return data;
+}
+#endif
+
+static void
+certificate_presented (MailStub *stub, const gnutls_datum_t *certs_der, int ncerts)
+{
+	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	MailStubExchangeCreds *creds = mse->creds;
+	int i;
+
+	ENTER;
+
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	if (creds->expected_cmd == CAMEL_STUB_CMD_CERTIFICATE_PRESENTED) {
+		creds->cert_der_ret_length = ncerts;
+		creds->cert_der_ret = g_new (gnutls_datum_t, ncerts);
+		for (i = 0; i < ncerts; i++) {
+			creds->cert_der_ret[i].size = certs_der[i].size;
+			creds->cert_der_ret[i].data = g_malloc (certs_der[i].size);
+			memcpy (creds->cert_der_ret[i].data, certs_der[i].data, certs_der[i].size);
+		}
+
+		creds->returned = TRUE;
+		g_cond_signal (creds->cond);
+	} else {
+		fprintf (stderr, "Got Spurious CERTIFICATE_PRESENTED; ignoring\n");
+	}
+
+	g_mutex_unlock (creds->cond_mutex);
+
+	EXIT;
+}
+
+static int
+stub_connect_ssl_cert_request (E2kCreds *ecreds,
+			       const gnutls_datum_t *req_ca_rdn_der,
+			       int nreqs,
+			       gnutls_datum_t **cert_der_ret,
+			       int *cert_der_ret_length)
+{
+	MailStubExchangeCreds *creds = (MailStubExchangeCreds *)ecreds;
+	GPtrArray *greqs;
+	MailStub *stub;
+	int i;
+
+	ENTER;
+
+	g_mutex_lock (creds->mutex);
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	g_object_ref (creds->mse);
+
+	creds->expected_cmd = CAMEL_STUB_CMD_CERTIFICATE_PRESENTED;
+
+	stub = MAIL_STUB (creds->mse);
+
+	greqs = g_ptr_array_sized_new (nreqs);
+	g_ptr_array_set_size (greqs, nreqs);
+	for (i = 0; i < nreqs; i++) {
+		g_ptr_array_index (greqs, i) = g_byte_array_new ();
+		datum_to_data (g_ptr_array_index (greqs, i), &req_ca_rdn_der[i]);
+	}
+
+	g_assert (!creds->returned);
+
+	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_CERTIFICATE_REQUESTED,
+			       CAMEL_STUB_ARG_BYTEARRAY_ARRAY, greqs,
+			       CAMEL_STUB_ARG_END);
+	mail_stub_push_changes (stub);
+
+	for (i = 0; i < nreqs; i++) {
+		g_byte_array_free (g_ptr_array_index (greqs, i), FALSE);
+	}
+	g_ptr_array_free (greqs, TRUE);
+
+	while (!creds->returned) {
+		g_cond_wait (creds->cond, creds->cond_mutex);
+	}
+	creds->returned = FALSE;
+
+	creds->expected_cmd = -1;
+
+	*cert_der_ret = creds->cert_der_ret;
+	creds->cert_der_ret = NULL;
+
+	*cert_der_ret_length = creds->cert_der_ret_length;
+	creds->cert_der_ret_length = -1;
+
+	g_object_unref (creds->mse);
+	g_mutex_unlock (creds->cond_mutex);
+	g_mutex_unlock (creds->mutex);
+
+	EXIT;
+
+	return 0;
+}
+
+static void
+data_signed (MailStub *stub, const gnutls_datum_t *signature)
+{
+	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
+	MailStubExchangeCreds *creds = mse->creds;
+
+	ENTER;
+
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	if (creds->expected_cmd == CAMEL_STUB_CMD_DATA_SIGNED) {
+		creds->signature->size = signature->size;
+		creds->signature->data = g_malloc (signature->size);
+		memcpy (creds->signature->data, signature->data, signature->size);
+		
+		creds->returned = TRUE;
+		g_cond_signal (creds->cond);
+	} else {
+		fprintf (stderr, "Got Spurious DATA_SIGNED; ignoring\n");
+	}
+
+	g_mutex_unlock (creds->cond_mutex);
+
+	EXIT;
+}
+
+static int
+stub_connect_ssl_cert_sign (E2kCreds *ecreds,
+			    const gnutls_datum_t *cert_der,
+			    const gnutls_datum_t *hash,
+			    gnutls_datum_t *signature)
+{
+	MailStubExchangeCreds *creds = (MailStubExchangeCreds *)ecreds;
+	MailStub *stub;
+
+	ENTER;
+
+	g_mutex_lock (creds->mutex);
+	g_mutex_lock (creds->cond_mutex);
+
+	HASLOCK;
+
+	g_object_ref (creds->mse);
+
+	creds->expected_cmd = CAMEL_STUB_CMD_DATA_SIGNED;
+
+	stub = MAIL_STUB (creds->mse);
+
+	creds->signature = signature;
+
+	g_assert (!creds->returned);
+
+	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_SIGN_DATA,
+			       CAMEL_STUB_ARG_BYTEARRAY, cert_der->data, cert_der->size,
+			       CAMEL_STUB_ARG_BYTEARRAY, hash->data, hash->size,
+			       CAMEL_STUB_ARG_END);
+	mail_stub_push_changes (stub);
+
+	while (!creds->returned) {
+		g_cond_wait (creds->cond, creds->cond_mutex);
+	}
+
+	creds->returned = FALSE;
+	creds->signature = NULL;
+	creds->expected_cmd = -1;
+
+	g_object_unref (creds->mse);
+	g_mutex_unlock (creds->cond_mutex);
+	g_mutex_unlock (creds->mutex);
+
+	EXIT;
+
+	return 0;
+}
+
+static void
+stub_connect_end (MailStubExchange *mse, E2kContext *ctx, int mode)
+{
+	MailStub *stub = MAIL_STUB (mse);
+	const char *uri;
+	int retval = 1;
+
+	if (mode == ONLINE_MODE) {
+		if (ctx) {
+			mse->ctx = g_object_ref (ctx);
+			
+			mse->mail_submission_uri = exchange_account_get_standard_uri (mse->account, "sendmsg");
+			uri = exchange_account_get_standard_uri (mse->account, "inbox");
+			mse->inbox = exchange_account_get_folder (mse->account, uri);
+			uri = exchange_account_get_standard_uri (mse->account, "deleteditems");
+			mse->deleted_items = exchange_account_get_folder (mse->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));
+		} else {
+			retval = 0;
+		}
+	}
+
+	mail_stub_return_data (stub, CAMEL_STUB_RETVAL_RESPONSE,
+			       CAMEL_STUB_ARG_UINT32, retval,
+			       CAMEL_STUB_ARG_END);
+
+	mail_stub_return_ok (stub);
+}
+
+static gpointer
+stub_connect_thread (gpointer user_data)
+{
+	MailStubExchangeCreds *creds = user_data;
+	ExchangeAccountResult result;
+	E2kContext *ctx;
+
+	ENTER;
+
+	ctx = exchange_account_connect (creds->mse->account, NULL, &result);
+	stub_connect_end (creds->mse, ctx, creds->mode);
+
+	g_object_unref (creds->mse);
+
+	EXIT;
+
+	return NULL;
+}
+
+static void
 stub_connect (MailStub *stub, char *pwd)
 {
 	MailStubExchange *mse = MAIL_STUB_EXCHANGE (stub);
 	ExchangeAccount *account;
-	ExchangeAccountResult result;
 	E2kContext *ctx;
-	guint32 retval = 1;
-	const char *uri;
 	int mode;
 
 	exchange_component_is_offline (global_exchange_component, &mode);
@@ -2832,38 +3240,16 @@
 		exchange_account_set_offline (account);
 
 	ctx = exchange_account_get_context (account);
-	if (!ctx) {
-		ctx = exchange_account_connect (account, pwd, &result);
+	if (ctx) {
+		stub_connect_end (mse, ctx, mode);
+		return;
 	}
-	
-	
-	if (!ctx && mode == ONLINE_MODE) {
-		retval = 0;
-		goto end;
-	} else if (mode == OFFLINE_MODE) {
-		goto end;
-	}
 
-	mse->ctx = g_object_ref (ctx);
+	mse->creds->mode = mode;
+	mse->creds->pwd = g_strdup (pwd);
+	g_object_ref (mse);
 
-	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);
-
-	/* 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);
+	g_thread_create (stub_connect_thread, mse->creds, FALSE, NULL);
 }
 
 #if 0
@@ -2944,8 +3330,23 @@
 	mail_stub_construct (stub, cmd_fd, status_fd);
 
 	mse = (MailStubExchange *)stub;
-	mse->account = account;
-	
+	mse->account = g_object_ref (account);
+
+	mse->creds = g_new0 (MailStubExchangeCreds, 1);
+
+	mse->creds->creds.http_auth_method = stub_connect_http_auth_method;
+	mse->creds->creds.http_authenticate = stub_connect_http_authenticate;
+	mse->creds->creds.ssl_cert_request = stub_connect_ssl_cert_request;
+	mse->creds->creds.ssl_cert_sign = stub_connect_ssl_cert_sign;
+
+	mse->creds->mutex = g_mutex_new ();
+	mse->creds->cond_mutex = g_mutex_new ();
+	mse->creds->cond = g_cond_new ();
+	mse->creds->returned = FALSE;
+	mse->creds->mse = mse;
+
+	exchange_account_add_creds (account, &mse->creds->creds);
+
 	/* offline_listener_handler_id = g_signal_connect (G_OBJECT (global_exchange_component),
 							"linestatus-changed",
 							G_CALLBACK (linestatus_listener), mse); */
Index: mail/mail-stub.c
===================================================================
--- mail/mail-stub.c	(revision 1359)
+++ mail/mail-stub.c	(working copy)
@@ -79,6 +79,23 @@
 	g_ptr_array_free (strings, TRUE);
 }
 
+#ifdef HAVE_GNOME_CERTAUTH
+static gnutls_datum_t *
+data_to_datum (gnutls_datum_t *datum, const GByteArray *data)
+{
+	datum->size = data->len;
+	datum->data = data->data;
+	return datum;
+}
+static GByteArray *
+datum_to_data (GByteArray *data, const gnutls_datum_t *datum)
+{
+	data->len = datum->size;
+	data->data = datum->data;
+	return data;
+}
+#endif
+
 static gboolean
 connection_handler (GIOChannel *source, GIOCondition condition, gpointer data)
 {
@@ -447,6 +464,67 @@
 		break;
 	}
 
+	case CAMEL_STUB_CMD_PASSWORD_PRESENTED:
+	{
+		char *password;
+
+		g_object_ref (stub);
+		if (!mail_stub_read_args (stub,
+					  CAMEL_STUB_ARG_STRING, &password,
+					  CAMEL_STUB_ARG_END))
+			goto comm_fail;
+
+		d(printf("PASSWORD_PRESENTED %s\n", password));
+		MS_CLASS (stub)->password_presented (stub, password);
+		g_free (password);
+		break;
+	}
+
+	case CAMEL_STUB_CMD_CERTIFICATE_PRESENTED:
+	{
+		GPtrArray *certs;
+		gnutls_datum_t *gcerts = NULL;
+		int ncerts;
+		int i;
+
+		g_object_ref (stub);
+		if (!mail_stub_read_args (stub,
+					  CAMEL_STUB_ARG_BYTEARRAY_ARRAY, &certs,
+					  CAMEL_STUB_ARG_END))
+			goto comm_fail;
+
+		d(printf("CERTIFICATE_PRESENTED %d certs\n", certs->len));
+		if (certs->len) {
+			gcerts = g_new (gnutls_datum_t, certs->len);
+			for (i = 0; i < certs->len; i++) {
+				data_to_datum (&gcerts[i], g_ptr_array_index (certs, i));
+			}
+		}
+		MS_CLASS (stub)->certificate_presented (stub, gcerts, certs->len);
+		for (i = 0; i < certs->len; i++) {
+			g_byte_array_free (g_ptr_array_index (certs, i), TRUE);
+		}
+		g_ptr_array_free (certs, TRUE);
+		g_free (gcerts);
+		break;
+	}
+
+	case CAMEL_STUB_CMD_DATA_SIGNED:
+	{
+		GByteArray *signature;
+		gnutls_datum_t gsignature;
+
+		g_object_ref (stub);
+		if (!mail_stub_read_args (stub,
+					  CAMEL_STUB_ARG_BYTEARRAY, &signature,
+					  CAMEL_STUB_ARG_END))
+			goto comm_fail;
+		d(printf("DATA_SIGNED %d bytes\n", signature->len));
+		MS_CLASS (stub)->data_signed (stub, data_to_datum (&gsignature, signature));
+		g_byte_array_free (signature, TRUE);
+		break;
+	}
+
 	default:
 		g_assert_not_reached ();
 		break;
@@ -563,7 +641,36 @@
 			break;
 		}
 		
-		
+		case CAMEL_STUB_ARG_BYTEARRAY_ARRAY:
+		{
+			GPtrArray **ret = va_arg (ap, GPtrArray **);
+
+			GByteArray *tmp;
+			int len;
+			int i;
+
+			status = camel_stub_marshal_decode_uint32 (stub->cmd, &len);
+			if (status == -1)
+				break;
+
+			*ret = g_ptr_array_sized_new (len);
+			g_ptr_array_set_size (*ret, len);
+			for (i = 0; i < len && status != -1; i++) {
+				status = camel_stub_marshal_decode_bytes (stub->cmd, &tmp);
+				if (status != -1) {
+					g_ptr_array_index (*ret, i) = tmp;
+				}
+			}
+			if (status == -1) {
+				for (--i; i >= 0; --i) {
+					g_byte_array_free (g_ptr_array_index (*ret, i), TRUE);
+				}
+				g_ptr_array_free (*ret, TRUE);
+				*ret = NULL;
+			}
+			break;
+		}
+
 		default:
 			g_assert_not_reached ();
 			status = -1;
@@ -668,8 +775,19 @@
 				camel_stub_marshal_encode_uint32 (marshal, g_array_index (arr, guint32, i));
 			break;
 		}
+
+		case CAMEL_STUB_ARG_BYTEARRAY_ARRAY:
+		{
+			GPtrArray *arr = va_arg (ap, GPtrArray *);
+			int i;
+
+			camel_stub_marshal_encode_uint32 (marshal, arr->len);
+			for (i = 0; i < arr->len; i++) {
+				camel_stub_marshal_encode_bytes (marshal, g_ptr_array_index (arr, i));
+			}
+			break;
+		}
 		
-		
 		default:
 			g_assert_not_reached ();
 			break;
Index: configure.in
===================================================================
--- configure.in	(revision 1359)
+++ configure.in	(working copy)
@@ -177,7 +177,18 @@
 	LIBSOUP_VERSION=2.2
 fi
 
-PKG_CHECK_MODULES(EXCHANGE_STORAGE, evolution-shell-$EVOLUTION_BASE_VERSION evolution-plugin-$EVOLUTION_BASE_VERSION libedataserverui-$EDS_API_VERSION libedata-book-$EDS_API_VERSION libedata-cal-$EDS_API_VERSION libsoup-$LIBSOUP_VERSION libglade-2.0 libgnomeui-2.0 libgnomeprint-2.2 >= 2.2.0 camel-provider-$EDS_API_VERSION)
+EXCHANGE_STORAGE_MODULES="evolution-shell-$EVOLUTION_BASE_VERSION evolution-plugin-$EVOLUTION_BASE_VERSION libedataserverui-$EDS_API_VERSION libedata-book-$EDS_API_VERSION libedata-cal-$EDS_API_VERSION libsoup-$LIBSOUP_VERSION libglade-2.0 libgnomeui-2.0 libgnomeprint-2.2 >= 2.2.0 camel-provider-$EDS_API_VERSION"
+NSS_MODULES="nss >= 3.11"
+PKG_CHECK_EXISTS([$NSS_MODULES], [
+	EXCHANGE_STORAGE_MODULES="$EXCHANGE_STORAGE_MODULES $NSS_MODULES"
+	AC_DEFINE(HAVE_NSS, 1, [Define if NSS is installed])
+])
+GCA_MODULES="gnome-certauth-0.0 >= 0.0"
+PKG_CHECK_EXISTS([$GCA_MODULES], [
+	EXCHANGE_STORAGE_MODULES="$EXCHANGE_STORAGE_MODULES $GCA_MODULES"
+	AC_DEFINE(HAVE_GNOME_CERTAUTH, 1, [Define if gnome-certauth is installed])
+])
+PKG_CHECK_MODULES(EXCHANGE_STORAGE, [$EXCHANGE_STORAGE_MODULES])
 AC_SUBST(EXCHANGE_STORAGE_CFLAGS)
 AC_SUBST(EXCHANGE_STORAGE_LIBS)
 
Index: addressbook/e-book-backend-exchange.c
===================================================================
--- addressbook/e-book-backend-exchange.c	(revision 1359)
+++ addressbook/e-book-backend-exchange.c	(working copy)
@@ -59,10 +59,18 @@
 #include <e-folder-exchange.h>
 #include "e-book-backend-exchange.h"
 #include "exchange-component.h"
+#include "exchange-gca-creds.h"
 
 #define DEBUG
-#define d(x)
+#define d(x) x
+#define GCA_TRACE(s, ...) d(fprintf (stderr, "%d:%s:%s():%d "s"\n", getpid(), __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__))
 
+#define GCA_TRACEMSG(s) GCA_TRACE("%s", (s))
+#define GCA_ENTER GCA_TRACEMSG("ENTER")
+#define GCA_EXIT GCA_TRACEMSG("EXIT")
+#define GCA_HASLOCK GCA_TRACEMSG("HAS LOCK")
+#define GCA_ALREADYLOCKED GCA_TRACEMSG("ALREADY LOCKED")
+
 #define SUMMARY_FLUSH_TIMEOUT 5000
 
 #define PARENT_TYPE E_TYPE_BOOK_BACKEND_SYNC
@@ -88,6 +96,9 @@
 
 	EBookBackendSummary *summary;
 	EBookBackendCache *cache;
+
+	GHashTable *creds;
+	GMutex *creds_mutex;
 };
 
 typedef struct PropMapping PropMapping;
@@ -2139,8 +2150,45 @@
 	return GNOME_Evolution_Addressbook_OtherError;
 }
 
+static void
+e_book_backend_exchange_add_client (EBookBackend *backend,
+				    EDataBook    *book)
+{
+	EBookBackendExchange *ebbe = E_BOOK_BACKEND_EXCHANGE (backend);
+	E2kCreds *creds;
+	ExchangeAccount *account;
+	GCA_ENTER;
+	account = exchange_component_get_account_for_uri (global_exchange_component, NULL);
+	creds = exchange_gca_creds_add (account, e_data_book_get_listener (book));
 
+	if (creds) {
+		GCA_TRACEMSG("have new creds");
+		g_mutex_lock (ebbe->priv->creds_mutex);
+		g_hash_table_insert (ebbe->priv->creds, book, creds);
+		g_mutex_unlock (ebbe->priv->creds_mutex);
+	}
+	GCA_EXIT;
+
+}
+
 static void
+e_book_backend_exchange_remove_client (EBookBackend *backend,
+				       EDataBook    *book)
+{
+	EBookBackendExchange *ebbe = E_BOOK_BACKEND_EXCHANGE (backend);
+	E2kCreds *creds;
+
+	g_mutex_lock (ebbe->priv->creds_mutex);
+	creds = g_hash_table_lookup (ebbe->priv->creds, book);
+	g_hash_table_remove (ebbe->priv->creds, book);
+	g_mutex_unlock (ebbe->priv->creds_mutex);
+
+	if (creds) {
+		exchange_gca_creds_remove (creds);
+	}
+}
+
+static void
 e_book_backend_exchange_authenticate_user (EBookBackend *backend,
 					   EDataBook        *book,
 					   guint32 	     opid,
@@ -2373,6 +2421,28 @@
 	return TRUE;
 }
 
+typedef struct {
+	EBookBackend    *backend;
+	ExchangeAccount *account;
+} SetModeData;
+
+static gpointer
+set_mode_thread (gpointer user_data)
+{
+	SetModeData *data = user_data;
+	ExchangeAccountResult result;
+
+	if (!exchange_account_connect (data->account, NULL, &result)) {
+		e_book_backend_notify_auth_required (data->backend);
+	}
+
+	g_object_unref (data->account);
+	g_object_unref (data->backend);
+	g_free (data);
+
+	return NULL;
+}
+
 static void
 e_book_backend_exchange_set_mode (EBookBackend *backend, int mode)
 {
@@ -2392,8 +2462,12 @@
 		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);
-		if (!exchange_account_get_context (account))
-			e_book_backend_notify_auth_required (backend);
+		if (!exchange_account_get_context (account)) {
+			SetModeData *data = g_new (SetModeData, 1);
+			data->account = g_object_ref (account);
+			data->backend = g_object_ref (backend);
+			g_thread_create (set_mode_thread, data, FALSE, NULL);
+		}
 	}
 	/*}*/
 }
@@ -2452,7 +2526,12 @@
 		if (be->priv->create_mutex)
 			g_mutex_free (be->priv->create_mutex);
 			
+		if (be->priv->creds_mutex)
+			g_mutex_free (be->priv->creds_mutex);
 
+		if (be->priv->creds)
+			g_hash_table_destroy (be->priv->creds);
+
 		g_free (be->priv);
 		be->priv = NULL;
 	}
@@ -2493,6 +2572,8 @@
 	backend_class->set_mode			= e_book_backend_exchange_set_mode;
 	backend_class->get_supported_auth_methods = e_book_backend_exchange_get_supported_auth_methods;
 	backend_class->authenticate_user     = e_book_backend_exchange_authenticate_user;
+	backend_class->add_client              = e_book_backend_exchange_add_client;
+	backend_class->remove_client           = e_book_backend_exchange_remove_client;
 
 	sync_class->remove_sync                = e_book_backend_exchange_remove;
 	sync_class->create_contact_sync        = e_book_backend_exchange_create_contact;
@@ -2521,6 +2602,8 @@
 	priv->is_writable 	= TRUE;
 
 	priv->create_mutex      = g_mutex_new ();
+	priv->creds_mutex       = g_mutex_new ();
+	priv->creds             = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	backend->priv 		= priv;
 }
Index: storage/exchange-config-listener.c
===================================================================
--- storage/exchange-config-listener.c	(revision 1359)
+++ storage/exchange-config-listener.c	(working copy)
@@ -67,6 +67,11 @@
 	int type;
 }FolderInfo;
 
+typedef struct {
+	E2kCreds creds;
+	ExchangeAccount *account;
+} AccountCreds;
+
 enum {
 	EXCHANGE_ACCOUNT_CREATED,
 	EXCHANGE_ACCOUNT_REMOVED,
Index: storage/exchange-gca-creds.c
===================================================================
--- storage/exchange-gca-creds.c	(revision 0)
+++ storage/exchange-gca-creds.c	(revision 0)
@@ -0,0 +1,164 @@
+#include "config.h"
+
+#include "exchange-gca-creds.h"
+
+#ifdef HAVE_GNOME_CERTAUTH
+#include <gnome-certauth/gca-certificate-listener.h>
+
+#include <glib/gthread.h>
+#include <bonobo/bonobo-main.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if 1
+#define GCA_TRACE(s, ...) fprintf (stderr, "%d:%s:%s():%d "s"\n", getpid(), __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)
+#else
+#define GCA_TRACE(s, ...)
+#endif
+
+#define GCA_TRACEMSG(s) GCA_TRACE("%s", (s))
+#define GCA_ENTER GCA_TRACEMSG("ENTER")
+#define GCA_EXIT GCA_TRACEMSG("EXIT")
+#define GCA_HASLOCK GCA_TRACEMSG("HAS LOCK")
+#define GCA_ALREADYLOCKED GCA_TRACEMSG("ALREADY LOCKED")
+
+typedef struct {
+    E2kCreds creds;
+    GMutex *mutex;
+    ExchangeAccount *account;
+    GcaCertificateListener *listener;
+    GNOME_CertificateAuthentication_CertificateSource source;
+} GcaCreds;
+
+static char *
+exchange_gca_creds_http_auth_method (E2kCreds *ecreds)
+{
+    GcaCreds *creds = (GcaCreds *)ecreds;
+    char *ret;
+    GCA_ENTER;
+    ret = exchange_account_get_authtype (creds->account);
+    GCA_EXIT;
+    return ret;
+}
+
+static void
+exchange_gca_creds_http_authenticate (E2kCreds *ecreds,
+                                      const char *auth_type, const char *auth_realm,
+                                      char **username, char **password)
+{
+    GcaCreds *creds = (GcaCreds *)ecreds;
+    GCA_ENTER;
+    *username = exchange_account_get_username (creds->account);
+    *password = exchange_account_get_password (creds->account);
+    GCA_ENTER;
+}
+
+static int
+exchange_gca_creds_ssl_cert_request (E2kCreds *ecreds,
+                                     const gnutls_datum_t *req_ca_rdn_der,
+                                     int nreqs,
+                                     gnutls_datum_t **cert_der_ret,
+                                     int *cert_der_ret_length)
+{
+    GcaCreds *creds = (GcaCreds *)ecreds;
+    GCA_ENTER;
+    g_mutex_lock (creds->mutex);
+    GCA_HASLOCK;
+    if (!creds->listener) {
+        creds->listener = GCA_CERTIFICATE_LISTENER (g_object_new (GCA_TYPE_CERTIFICATE_LISTENER,
+                                                                  "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST),
+                                                                  NULL));
+    }
+    g_mutex_unlock (creds->mutex);
+    gca_certificate_listener_request_certificate (
+        creds->listener, creds->source,
+        req_ca_rdn_der, nreqs, 
+        cert_der_ret, cert_der_ret_length);
+    GCA_EXIT;
+    return 0;
+}
+
+static int
+exchange_gca_creds_ssl_cert_sign (E2kCreds *ecreds,
+                                  const gnutls_datum_t *cert_der,
+                                  const gnutls_datum_t *hash_data,
+                                  gnutls_datum_t *sig_data)
+{
+    GcaCreds *creds = (GcaCreds *)ecreds;
+    GCA_ENTER;
+    g_mutex_lock (creds->mutex);
+    GCA_HASLOCK;
+    if (!creds->listener) {
+        creds->listener = GCA_CERTIFICATE_LISTENER (g_object_new (GCA_TYPE_CERTIFICATE_LISTENER, 
+                                                                  "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST),
+                                                                  NULL));
+    }
+    g_mutex_unlock (creds->mutex);
+    gca_certificate_listener_sign_data (
+        creds->listener, creds->source,
+        cert_der, hash_data, sig_data);
+    GCA_EXIT;
+    return 0;
+}
+#endif /* HAVE_GNOME_CERTAUTH */
+
+void
+exchange_gca_creds_remove (E2kCreds *ecreds)
+{
+#ifdef HAVE_GNOME_CERTAUTH
+    GcaCreds *creds = (GcaCreds *)ecreds;
+
+    fprintf (stderr, "%s: killing creds!\n", G_GNUC_PRETTY_FUNCTION);
+
+    g_mutex_lock (creds->mutex);
+    exchange_account_remove_creds (creds->account, &creds->creds);
+    g_mutex_unlock (creds->mutex);
+    g_mutex_free (creds->mutex);
+    if (creds->listener) {
+        g_object_unref (creds->listener);
+    }
+    g_free (creds);
+#endif /* HAVE_GNOME_CERTAUTH */
+}
+
+E2kCreds *
+exchange_gca_creds_add (ExchangeAccount *account,
+                        Bonobo_Unknown   source)
+{
+#ifdef HAVE_GNOME_CERTAUTH
+    GcaCreds *creds;
+    CORBA_Environment ev;
+    GNOME_CertificateAuthentication_CertificateSource corba_source;
+    
+    CORBA_exception_init (&ev);
+    corba_source = bonobo_object_query_remote (
+        source,
+        "IDL:GNOME/CertificateAuthentication/CertificateSource:1.0",
+        &ev);
+    CORBA_exception_free (&ev);
+    
+    if (!corba_source) {
+        fprintf (stderr, "%s: listener is not a certificate source\n", G_GNUC_PRETTY_FUNCTION);
+        return NULL;
+    }
+    
+    creds = g_new0 (GcaCreds, 1);
+    creds->source = corba_source;
+    creds->account = account;
+    creds->mutex = g_mutex_new ();
+    creds->listener = NULL;
+    creds->creds.http_auth_method  = exchange_gca_creds_http_auth_method;
+    creds->creds.http_authenticate = exchange_gca_creds_http_authenticate;
+    creds->creds.ssl_cert_request  = exchange_gca_creds_ssl_cert_request;
+    creds->creds.ssl_cert_sign     = exchange_gca_creds_ssl_cert_sign;
+    
+    exchange_account_add_creds (account, &creds->creds);
+    
+    /* bonobo_object_set_immoral (BONOBO_OBJECT (book), TRUE); */
+    /* g_object_weak_ref (G_OBJECT (book), book_remove_creds, creds); */
+    
+    return &creds->creds;
+#else /* !HAVE_GNOME_CERTAUTH */
+    return NULL;
+#endif /* !HAVE_GNOME_CERTAUTH */
+}
Index: storage/exchange-gca-creds.h
===================================================================
--- storage/exchange-gca-creds.h	(revision 0)
+++ storage/exchange-gca-creds.h	(revision 0)
@@ -0,0 +1,13 @@
+#ifndef EXCHANGE_GCA_CREDS_H
+#define EXCHANGE_GCA_CREDS_H
+
+#include <exchange/exchange-account.h>
+#include <bonobo/bonobo-object.h>
+
+E2kCreds *exchange_gca_creds_add (ExchangeAccount *account,
+                                  Bonobo_Unknown   source);
+
+void exchange_gca_creds_remove (E2kCreds *creds);
+
+#endif /* EXCHANGE_GCA_CREDS_H */
+
Index: storage/main.c
===================================================================
--- storage/main.c	(revision 1359)
+++ storage/main.c	(working copy)
@@ -235,6 +235,8 @@
 	}
 #endif
 
+	e_passwords_init ();
+
 	bonobo_main ();
 
 	e_passwords_shutdown ();
Index: storage/Makefile.am
===================================================================
--- storage/Makefile.am	(revision 1359)
+++ storage/Makefile.am	(working copy)
@@ -23,19 +23,21 @@
 	exchange-connector-setup				\
 	migr-test
 
-evolution_exchange_storage_SOURCES =				\
-	exchange-autoconfig-wizard.c				\
-	exchange-autoconfig-wizard.h				\
-	exchange-component.c					\
-	exchange-component.h					\
-	exchange-config-listener.c				\
-	exchange-config-listener.h				\
-	exchange-change-password.c				\
-	exchange-change-password.h				\
-	exchange-migrate.c					\
-	exchange-migrate.h					\
-	exchange-storage.c					\
-	exchange-storage.h					\
+evolution_exchange_storage_SOURCES =				 \
+	exchange-autoconfig-wizard.c				 \
+	exchange-autoconfig-wizard.h				 \
+	exchange-component.c					 \
+	exchange-component.h					 \
+	exchange-config-listener.c				 \
+	exchange-config-listener.h				 \
+	exchange-change-password.c				 \
+	exchange-change-password.h				 \
+	exchange-gca-creds.c					 \
+	exchange-gca-creds.h					 \
+	exchange-migrate.c					 \
+	exchange-migrate.h					 \
+	exchange-storage.c					 \
+	exchange-storage.h					 \
 	main.c							
 
 evolution_exchange_storage_LDADD =				\
Index: calendar/e-cal-backend-exchange.c
===================================================================
--- calendar/e-cal-backend-exchange.c	(revision 1359)
+++ calendar/e-cal-backend-exchange.c	(working copy)
@@ -48,6 +48,7 @@
 #include <e-folder-exchange.h>
 #include "exchange-component.h"
 #include <exchange-hierarchy.h>
+#include "exchange-gca-creds.h"
 
 struct ECalBackendExchangePrivate {
 	gboolean read_only;
@@ -312,6 +313,7 @@
 	E2kUri *euri = NULL;
 	int nresults = 0;
 	guint access = 0;
+	E2kCreds *creds;
 
 	d(printf("ecbe_open_calendar(%p, %p, %sonly if exists, user=%s, pass=%s)\n", backend, cal, only_if_exists?"":"not ", username?username:"(null)", password?password:"(null)"));
 
@@ -371,6 +373,7 @@
 	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);
+		creds = exchange_gca_creds_add (cbex->account, e_data_cal_get_listener (cal));
 		exchange_account_set_online (cbex->account);
 		if (!exchange_account_connect (cbex->account, password, &acresult)) {
 			g_mutex_unlock (cbex->priv->open_lock);
@@ -380,6 +383,7 @@
 	}
 
 	if (exchange_account_get_context (cbex->account)) {
+		creds = exchange_gca_creds_add (cbex->account, e_data_cal_get_listener (cal));
 		exchange_account_set_online (cbex->account);
 		if(!exchange_account_connect (cbex->account, password, &acresult)) {
 			g_mutex_unlock (cbex->priv->open_lock);
