[evolution-mapi] Bug #608327 - Cannot recover after connection lost (book/cal parts)



commit 467b2c3fc167c4b4eb5d73c1035211d6af68fbf7
Author: Milan Crha <mcrha redhat com>
Date:   Tue Jul 17 11:32:49 2012 +0200

    Bug #608327 - Cannot recover after connection lost (book/cal parts)

 src/addressbook/e-book-backend-mapi-contacts.c |  112 ++++++++--
 src/addressbook/e-book-backend-mapi-gal.c      |   42 +++-
 src/addressbook/e-book-backend-mapi.c          |  113 ++++++++--
 src/addressbook/e-book-backend-mapi.h          |   46 +++--
 src/calendar/e-cal-backend-mapi.c              |  265 ++++++++++++++++++------
 src/libexchangemapi/e-mapi-connection.c        |   78 ++++---
 6 files changed, 493 insertions(+), 163 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
index 8265c2e..795a146 100644
--- a/src/addressbook/e-book-backend-mapi-contacts.c
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -360,25 +360,29 @@ ebbm_contacts_connection_status_changed (EBookBackendMAPI *ebma, gboolean is_onl
 		EMapiConnection *conn;
 		mapi_object_t obj_folder;
 		gboolean status;
+		GError *mapi_error = NULL;
 
 		e_book_backend_mapi_lock_connection (ebma);
 
-		conn = e_book_backend_mapi_get_connection (ebma);
+		conn = e_book_backend_mapi_get_connection (ebma, NULL, NULL);
 		if (!conn) {
 			e_book_backend_mapi_unlock_connection (ebma);
 			return;
 		}
 
-		status = ebbm_contacts_open_folder (E_BOOK_BACKEND_MAPI_CONTACTS (ebma), conn, &obj_folder, NULL, NULL);
+		status = ebbm_contacts_open_folder (E_BOOK_BACKEND_MAPI_CONTACTS (ebma), conn, &obj_folder, NULL, &mapi_error);
 
 		if (status) {
 			e_mapi_connection_enable_notifications (conn, &obj_folder,
 				fnevObjectCreated | fnevObjectModified | fnevObjectDeleted | fnevObjectMoved | fnevObjectCopied,
-				NULL, NULL);
+				NULL, &mapi_error);
 
-			e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
+			e_mapi_connection_close_folder (conn, &obj_folder, NULL, &mapi_error);
 		}
 
+		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+		g_clear_error (&mapi_error);
+
 		g_signal_connect (conn, "server-notification", G_CALLBACK (ebbmc_server_notification_cb), ebma);
 
 		e_book_backend_mapi_unlock_connection (ebma);
@@ -411,9 +415,13 @@ ebbm_contacts_remove (EBookBackendMAPI *ebma, GCancellable *cancellable, GError
 
 		e_book_backend_mapi_lock_connection (ebma);
 
-		conn = e_book_backend_mapi_get_connection (ebma);
+		conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 		if (!conn) {
-			g_propagate_error (error, EDB_ERROR (OFFLINE_UNAVAILABLE));
+			if (!mapi_error)
+				g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+			else
+				mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+			g_clear_error (&mapi_error);
 		} else {
 			mapi_object_t *obj_store = NULL;
 
@@ -422,6 +430,7 @@ ebbm_contacts_remove (EBookBackendMAPI *ebma, GCancellable *cancellable, GError
 
 			if (mapi_error) {
 				mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to remove public folder"));
+				e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
 				g_error_free (mapi_error);
 			}
 		}
@@ -462,10 +471,16 @@ ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
 		e_book_backend_mapi_unlock_connection (ebma);
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -488,6 +503,7 @@ ebbm_contacts_create_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
 	e_book_backend_mapi_unlock_connection (ebma);
 
 	if (!mid) {
@@ -535,10 +551,16 @@ ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
 		e_book_backend_mapi_unlock_connection (ebma);
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -562,6 +584,7 @@ ebbm_contacts_remove_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
 	e_book_backend_mapi_unlock_connection (ebma);
 
 	if (mapi_error) {
@@ -607,10 +630,16 @@ ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
 		e_book_backend_mapi_unlock_connection (ebma);
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -638,6 +667,7 @@ ebbm_contacts_modify_contacts (EBookBackendMAPI *ebma, GCancellable *cancellable
 			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 		}
 
+		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
 		if (!status) {
 			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to modify item on a server"));
 			if (mapi_error)
@@ -691,10 +721,16 @@ ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, co
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
 		e_book_backend_mapi_unlock_connection (ebma);
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -722,6 +758,8 @@ ebbm_contacts_get_contact (EBookBackendMAPI *ebma, GCancellable *cancellable, co
 		*vcard =  e_vcard_to_string (E_VCARD (tc.contact), EVC_FORMAT_VCARD_30);
 		g_object_unref (tc.contact);
 	} else {
+		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 		if (!mapi_error || mapi_error->code == MAPI_E_NOT_FOUND) {
 			g_propagate_error (error, EDB_ERROR (CONTACT_NOT_FOUND));
 		} else {
@@ -772,10 +810,15 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
 
 		return;
 	}
@@ -799,6 +842,8 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
 		g_slist_free_full (mids, g_free);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 	if (!status) {
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch items from a server"));
 		if (mapi_error)
@@ -847,10 +892,16 @@ ebbm_contacts_get_contacts_count (EBookBackendMAPI *ebma,
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -868,6 +919,8 @@ ebbm_contacts_get_contacts_count (EBookBackendMAPI *ebma,
 		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 	if (mapi_error) {
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to count server contacts"));
 		g_error_free (mapi_error);
@@ -901,10 +954,16 @@ ebbm_contacts_list_known_uids (EBookBackendMAPI *ebma,
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -918,6 +977,8 @@ ebbm_contacts_list_known_uids (EBookBackendMAPI *ebma,
 		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 	if (mapi_error) {
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to list items from a server"));
 		g_error_free (mapi_error);
@@ -953,10 +1014,15 @@ ebbm_contacts_transfer_contacts (EBookBackendMAPI *ebma,
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
 
 		return;
 	}
@@ -992,6 +1058,8 @@ ebbm_contacts_transfer_contacts (EBookBackendMAPI *ebma,
 		g_slist_free_full (mids, g_free);
 	}
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 	if (!status) {
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to transfer contacts from a server"));
 
diff --git a/src/addressbook/e-book-backend-mapi-gal.c b/src/addressbook/e-book-backend-mapi-gal.c
index d92fab2..cf1c7dd 100644
--- a/src/addressbook/e-book-backend-mapi-gal.c
+++ b/src/addressbook/e-book-backend-mapi-gal.c
@@ -178,10 +178,16 @@ ebbm_gal_transfer_contacts (EBookBackendMAPI *ebma,
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
@@ -218,6 +224,8 @@ ebbm_gal_transfer_contacts (EBookBackendMAPI *ebma,
 	status = e_mapi_connection_transfer_gal_objects	(conn, get_mids, NULL, NULL, transfer_gal_cb, &tg, cancellable, &mapi_error);
 
 	if (mapi_error) {
+		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
 		g_error_free (mapi_error);
 	} else if (!status) {
@@ -236,22 +244,35 @@ ebbm_gal_get_contacts_count (EBookBackendMAPI *ebma,
 			     GError **error)
 {
 	EMapiConnection *conn;
+	GError *mapi_error = NULL;
 
 	e_return_data_book_error_if_fail (ebma != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (obj_total != NULL, E_DATA_BOOK_STATUS_INVALID_ARG);
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
-	if (!e_mapi_connection_count_gal_objects (conn, obj_total, cancellable, error))
+	if (!e_mapi_connection_count_gal_objects (conn, obj_total, cancellable, &mapi_error))
 		*obj_total = -1;
 
+	e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
+	if (mapi_error) {
+		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
+		g_clear_error (&mapi_error);
+	}
+
 	e_book_backend_mapi_unlock_connection (ebma);
 }
 
@@ -272,16 +293,23 @@ ebbm_gal_list_known_uids (EBookBackendMAPI *ebma,
 
 	e_book_backend_mapi_lock_connection (ebma);
 
-	conn = e_book_backend_mapi_get_connection (ebma);
+	conn = e_book_backend_mapi_get_connection (ebma, cancellable, &mapi_error);
 	if (!conn) {
 		e_book_backend_mapi_unlock_connection (ebma);
-		g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+
+		if (!mapi_error)
+			g_propagate_error (error, EDB_ERROR (REPOSITORY_OFFLINE));
+		else
+			mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE, NULL);
+		g_clear_error (&mapi_error);
+
 		return;
 	}
 
 	e_mapi_connection_list_gal_objects (conn, build_rs_cb, build_rs_cb_data, list_gal_uids_cb, lku, cancellable, &mapi_error);
 
 	if (mapi_error) {
+		e_book_backend_mapi_maybe_disconnect (ebma, mapi_error);
 		mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Failed to fetch GAL entries"));
 		g_error_free (mapi_error);
 	}
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index d61306f..6adab9e 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -51,7 +51,7 @@ struct _EBookBackendMAPIPrivate
 {
 	EMapiOperationQueue *op_queue;
 
-	GMutex *conn_lock;
+	GRecMutex conn_lock;
 	EMapiConnection *conn;
 	gchar *book_uid;
 	gboolean marked_for_offline;
@@ -69,7 +69,7 @@ struct _EBookBackendMAPIPrivate
 	gboolean server_dirty;
 
 	GHashTable *running_views; /* EDataBookView => GCancellable */
-	GMutex *running_views_lock;
+	GMutex running_views_lock;
 };
 
 static CamelMapiSettings *
@@ -398,15 +398,16 @@ ebbm_connect_user (EBookBackendMAPI *ebma,
 			g_object_unref (old_conn);
 
 		if (!priv->conn || mapi_error) {
-			gboolean is_network_error = g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR);
+			gboolean is_network_error = g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR) ||
+				(mapi_error && mapi_error->domain != E_MAPI_ERROR);
 
 			if (priv->conn) {
 				g_object_unref (priv->conn);
 				priv->conn = NULL;
 			}
 
-			if (!is_network_error)
-				mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, _("Cannot connect"));
+			if (is_network_error)
+				mapi_error_to_edb_error (error, mapi_error, E_DATA_BOOK_STATUS_OTHER_ERROR, NULL);
 			e_book_backend_mapi_unlock_connection (ebma);
 
 			if (mapi_error)
@@ -429,6 +430,63 @@ ebbm_connect_user (EBookBackendMAPI *ebma,
 	return E_SOURCE_AUTHENTICATION_ACCEPTED;
 }
 
+/* connection lock should be already held when calling this function */
+gboolean
+e_book_backend_mapi_ensure_connected (EBookBackendMAPI *ebma,
+				      GCancellable *cancellable, 
+				      GError **error)
+{
+	CamelMapiSettings *settings;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
+
+	if (ebma->priv->conn && e_mapi_connection_connected (ebma->priv->conn))
+		return TRUE;
+
+	settings = ebbm_get_collection_settings (ebma);
+
+	if (!camel_mapi_settings_get_kerberos (settings) ||
+	    ebbm_connect_user (ebma, cancellable, NULL, &local_error) != E_SOURCE_AUTHENTICATION_ACCEPTED) {
+		ESourceRegistry *registry;
+
+		registry = e_book_backend_get_registry (E_BOOK_BACKEND (ebma));
+
+		e_source_registry_authenticate_sync (
+			registry, e_backend_get_source (E_BACKEND (ebma)),
+			E_SOURCE_AUTHENTICATOR (ebma),
+			cancellable, &local_error);
+	}
+
+	if (!local_error)
+		return TRUE;
+
+	g_propagate_error (error, local_error);
+
+	return FALSE;
+}
+
+/* connection lock should be already held when calling this function */
+void
+e_book_backend_mapi_maybe_disconnect (EBookBackendMAPI *ebma,
+				      const GError *mapi_error)
+{
+	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
+
+	/* no error or already disconnected */
+	if (!mapi_error || !ebma->priv->conn)
+		return;
+
+	if (g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR) ||
+	    g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
+		e_mapi_connection_disconnect (ebma->priv->conn,
+			!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR),
+			NULL, NULL);
+		g_object_unref (ebma->priv->conn);
+		ebma->priv->conn = NULL;
+	}
+}
+
 static void
 ebbm_open (EBookBackendMAPI *ebma,
 	   GCancellable *cancellable,
@@ -492,7 +550,7 @@ ebbm_open (EBookBackendMAPI *ebma,
 
 	e_book_backend_notify_online (E_BOOK_BACKEND (ebma), TRUE);
 
-
+	e_book_backend_mapi_ensure_connected (ebma, cancellable, &error);
 	if (!camel_mapi_settings_get_kerberos (settings) ||
 	    ebbm_connect_user (ebma, cancellable, NULL, &error) != E_SOURCE_AUTHENTICATION_ACCEPTED) {
 		ESourceRegistry *registry;
@@ -1023,7 +1081,7 @@ ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
 			GError *err = NULL;
 			struct BookViewThreadData *bvtd = g_new0 (struct BookViewThreadData, 1);
 
-			g_mutex_lock (ebma->priv->running_views_lock);
+			g_mutex_lock (&ebma->priv->running_views_lock);
 
 			bvtd->ebma = g_object_ref (ebma);
 			bvtd->book_view = g_object_ref (opbv->book_view);
@@ -1032,7 +1090,7 @@ ebbm_operation_cb (OperationBase *op, gboolean cancelled, EBookBackend *backend)
 			if (bvtd->cancellable)
 				g_object_ref (bvtd->cancellable);
 
-			g_mutex_unlock (ebma->priv->running_views_lock);
+			g_mutex_unlock (&ebma->priv->running_views_lock);
 
 			g_thread_create (ebbm_book_view_thread, bvtd, FALSE, &err);
 
@@ -1259,9 +1317,9 @@ ebbm_op_start_book_view (EBookBackend *backend, EDataBookView *book_view)
 	op->base.opid = 0;
 	op->book_view = g_object_ref (book_view);
 
-	g_mutex_lock (priv->running_views_lock);
+	g_mutex_lock (&priv->running_views_lock);
 	g_hash_table_insert (priv->running_views, book_view, g_cancellable_new ());
-	g_mutex_unlock (priv->running_views_lock);
+	g_mutex_unlock (&priv->running_views_lock);
 
 	e_mapi_operation_queue_push (priv->op_queue, op);
 }
@@ -1290,12 +1348,12 @@ ebbm_op_stop_book_view (EBookBackend *backend, EDataBookView *book_view)
 	op->base.opid = 0;
 	op->book_view = g_object_ref (book_view);
 
-	g_mutex_lock (priv->running_views_lock);
+	g_mutex_lock (&priv->running_views_lock);
 	cancellable = g_hash_table_lookup (priv->running_views, book_view);
 	if (cancellable)
 		g_cancellable_cancel (cancellable);
 	g_hash_table_remove (priv->running_views, book_view);
-	g_mutex_unlock (priv->running_views_lock);
+	g_mutex_unlock (&priv->running_views_lock);
 
 	e_mapi_operation_queue_push (priv->op_queue, op);
 }
@@ -1307,8 +1365,8 @@ e_book_backend_mapi_init (EBookBackendMAPI *ebma)
 
 	ebma->priv->op_queue = e_mapi_operation_queue_new ((EMapiOperationQueueFunc) ebbm_operation_cb, ebma);
 	ebma->priv->running_views = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
-	ebma->priv->running_views_lock = g_mutex_new ();
-	ebma->priv->conn_lock = g_mutex_new ();
+	g_mutex_init (&ebma->priv->running_views_lock);
+	g_rec_mutex_init (&ebma->priv->conn_lock);
 
 	ebma->priv->update_cache = g_cancellable_new ();
 	ebma->priv->update_cache_thread = NULL;
@@ -1349,8 +1407,8 @@ ebbm_dispose (GObject *object)
 		FREE (priv->book_uid);
 
 		g_hash_table_destroy (priv->running_views);
-		g_mutex_free (priv->running_views_lock);
-		g_mutex_free (priv->conn_lock);
+		g_mutex_clear (&priv->running_views_lock);
+		g_rec_mutex_clear (&priv->conn_lock);
 
 		#undef UNREF
 		#undef FREE
@@ -1416,9 +1474,8 @@ e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
 	g_return_if_fail (ebma->priv != NULL);
-	g_return_if_fail (ebma->priv->conn_lock != NULL);
 
-	g_mutex_lock (ebma->priv->conn_lock);
+	g_rec_mutex_lock (&ebma->priv->conn_lock);
 }
 
 void
@@ -1426,17 +1483,27 @@ e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma));
 	g_return_if_fail (ebma->priv != NULL);
-	g_return_if_fail (ebma->priv->conn_lock != NULL);
 
-	g_mutex_unlock (ebma->priv->conn_lock);
+	g_rec_mutex_unlock (&ebma->priv->conn_lock);
 }
 
 EMapiConnection *
-e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma)
+e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma,
+				    GCancellable *cancellable,
+				    GError **perror)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), NULL);
 	g_return_val_if_fail (ebma->priv != NULL, NULL);
 
+	if (ebma->priv->conn)
+		return ebma->priv->conn;
+
+	if (!e_backend_get_online (E_BACKEND (ebma)))
+		return NULL;
+
+	if (!e_book_backend_mapi_ensure_connected (ebma, cancellable, perror))
+		return NULL;
+
 	return ebma->priv->conn;
 }
 
@@ -1458,9 +1525,9 @@ e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView
 	g_return_val_if_fail (E_IS_BOOK_BACKEND_MAPI (ebma), FALSE);
 	g_return_val_if_fail (ebma->priv != NULL, FALSE);
 
-	g_mutex_lock (ebma->priv->running_views_lock);
+	g_mutex_lock (&ebma->priv->running_views_lock);
 	res = g_hash_table_lookup (ebma->priv->running_views, book_view) != NULL;
-	g_mutex_unlock (ebma->priv->running_views_lock);
+	g_mutex_unlock (&ebma->priv->running_views_lock);
 
 	return res;
 }
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index 97e6429..358ed2a 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -97,19 +97,39 @@ typedef struct
 
 GType e_book_backend_mapi_get_type (void);
 
-const gchar *e_book_backend_mapi_get_book_uid (EBookBackendMAPI *ebma);
-void e_book_backend_mapi_lock_connection (EBookBackendMAPI *ebma);
-void e_book_backend_mapi_unlock_connection (EBookBackendMAPI *ebma);
-EMapiConnection *e_book_backend_mapi_get_connection (EBookBackendMAPI *ebma);
-void e_book_backend_mapi_get_db (EBookBackendMAPI *ebma, EBookBackendSqliteDB **db);
-gboolean e_book_backend_mapi_book_view_is_running (EBookBackendMAPI *ebma, EDataBookView *book_view);
-void e_book_backend_mapi_update_view_by_cache (EBookBackendMAPI *ebma, EDataBookView *book_view, GError **error);
-gboolean e_book_backend_mapi_is_marked_for_offline (EBookBackendMAPI *ebma);
-gboolean e_book_backend_mapi_notify_contact_update (EBookBackendMAPI *ebma, EDataBookView *book_view, EContact *contact, gint index, gint total, gpointer notify_contact_data);
-void e_book_backend_mapi_notify_contact_removed (EBookBackendMAPI *ebma, const gchar *uid);
-void   e_book_backend_mapi_cache_set (EBookBackendMAPI *ebma, const gchar *key, const gchar *value);
-gchar *e_book_backend_mapi_cache_get (EBookBackendMAPI *ebma, const gchar *key);
-void e_book_backend_mapi_refresh_cache (EBookBackendMAPI *ebma);
+const gchar *		e_book_backend_mapi_get_book_uid (EBookBackendMAPI *ebma);
+void			e_book_backend_mapi_lock_connection		(EBookBackendMAPI *ebma);
+void			e_book_backend_mapi_unlock_connection		(EBookBackendMAPI *ebma);
+EMapiConnection *	e_book_backend_mapi_get_connection		(EBookBackendMAPI *ebma,
+									 GCancellable *cancellable,
+									 GError **perror);
+gboolean		e_book_backend_mapi_ensure_connected		(EBookBackendMAPI *ebma,
+									 GCancellable *cancellable, 
+									 GError **error);
+void			e_book_backend_mapi_maybe_disconnect		(EBookBackendMAPI *ebma,
+									 const GError *mapi_error);
+void			e_book_backend_mapi_get_db			(EBookBackendMAPI *ebma,
+									 EBookBackendSqliteDB **db);
+gboolean		e_book_backend_mapi_book_view_is_running	(EBookBackendMAPI *ebma,
+									 EDataBookView *book_view);
+void			e_book_backend_mapi_update_view_by_cache	(EBookBackendMAPI *ebma,
+									 EDataBookView *book_view,
+									 GError **error);
+gboolean		e_book_backend_mapi_is_marked_for_offline	(EBookBackendMAPI *ebma);
+gboolean		e_book_backend_mapi_notify_contact_update	(EBookBackendMAPI *ebma,
+									 EDataBookView *book_view,
+									 EContact *contact,
+									 gint index,
+									 gint total,
+									 gpointer notify_contact_data);
+void			e_book_backend_mapi_notify_contact_removed	(EBookBackendMAPI *ebma,
+									 const gchar *uid);
+void			e_book_backend_mapi_cache_set			(EBookBackendMAPI *ebma,
+									 const gchar *key,
+									 const gchar *value);
+gchar *			e_book_backend_mapi_cache_get			(EBookBackendMAPI *ebma,
+									 const gchar *key);
+void			e_book_backend_mapi_refresh_cache		(EBookBackendMAPI *ebma);
 
 /* utility functions/macros */
 
diff --git a/src/calendar/e-cal-backend-mapi.c b/src/calendar/e-cal-backend-mapi.c
index 776a43e..79f0a7a 100644
--- a/src/calendar/e-cal-backend-mapi.c
+++ b/src/calendar/e-cal-backend-mapi.c
@@ -152,6 +152,9 @@ ecbm_open_folder (ECalBackendMAPI *ecbm,
 	return res;
 }
 
+static EMapiConnection *e_cal_backend_mapi_get_connection	(ECalBackendMAPI *cbma, GCancellable *cancellable, GError **perror);
+static void		e_cal_backend_mapi_maybe_disconnect	(ECalBackendMAPI *cbma, const GError *mapi_error);
+
 #define CACHE_REFRESH_INTERVAL 600000
 
 static GStaticMutex auth_mutex = G_STATIC_MUTEX_INIT;
@@ -385,16 +388,26 @@ ecbm_remove (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, GEr
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
 	priv = cbmapi->priv;
 
-	if (!e_backend_get_online (E_BACKEND (backend)) || !priv->conn || !e_mapi_connection_connected (priv->conn)) {
+	if (!e_backend_get_online (E_BACKEND (backend))) {
 		g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
 		return;
 	}
+
 	if (!priv->is_public_folder && !priv->foreign_username) {
+		EMapiConnection *conn;
 		GError *mapi_error = NULL;
 		mapi_object_t *obj_store = NULL;
 
-		if (!e_mapi_connection_peek_store (priv->conn, priv->foreign_username ? FALSE : priv->is_public_folder, priv->foreign_username, &obj_store, cancellable, &mapi_error) ||
-		    !e_mapi_connection_remove_folder (priv->conn, obj_store, priv->fid, cancellable, &mapi_error)) {
+		conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+		if (!conn) {
+			if (!mapi_error)
+				g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
+			else
+				mapi_error_to_edc_error (perror, mapi_error, RepositoryOffline, NULL);
+			e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+			g_clear_error (&mapi_error);
+		} else if (!e_mapi_connection_peek_store (conn, priv->foreign_username ? FALSE : priv->is_public_folder, priv->foreign_username, &obj_store, cancellable, &mapi_error) ||
+		           !e_mapi_connection_remove_folder (conn, obj_store, priv->fid, cancellable, &mapi_error)) {
 			mapi_error_to_edc_error (perror, mapi_error, OtherError, _("Failed to remove public folder"));
 			if (mapi_error)
 				g_error_free (mapi_error);
@@ -552,6 +565,8 @@ notify_error_ex (ECalBackendMAPI *mapi_backend, GError **perror, const gchar *fo
 	e_cal_backend_notify_error (E_CAL_BACKEND (mapi_backend), msg);
 	g_free (msg);
 
+	if (perror)
+		e_cal_backend_mapi_maybe_disconnect (mapi_backend, *perror);
 	g_clear_error (perror);
 }
 
@@ -806,7 +821,13 @@ update_local_cache (ECalBackendMAPI *cbmapi, GCancellable *cancellable)
 
 	g_mutex_lock (priv->updating_mutex);
 
-	conn = g_object_ref (priv->conn);
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+	if (!conn) {
+		g_clear_error (&mapi_error);
+		goto cleanup;
+	}
+
+	g_object_ref (conn);
 
 	success = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
 	if (!success) {
@@ -910,7 +931,8 @@ update_local_cache (ECalBackendMAPI *cbmapi, GCancellable *cancellable)
 	}
 
  cleanup:
-	g_object_unref (conn);
+	if (conn)
+		g_object_unref (conn);
 	g_mutex_unlock (priv->updating_mutex);
 
 	g_mutex_lock (priv->is_updating_mutex);
@@ -1237,10 +1259,11 @@ ecbm_connect_user (ECalBackend *backend,
 			g_signal_connect (priv->conn, "server-notification", G_CALLBACK (ecbm_server_notification_cb), cbmapi);
 		}
 	} else {
-		gboolean is_network_error = g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR);
+		gboolean is_network_error = g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR) ||
+			(mapi_error && mapi_error->domain != E_MAPI_ERROR);
 
-		if (!is_network_error)
-			mapi_error_to_edc_error (perror, mapi_error, is_network_error ? OtherError : AuthenticationFailed, NULL);
+		if (is_network_error)
+			mapi_error_to_edc_error (perror, mapi_error, OtherError, NULL);
 		if (mapi_error)
 			g_error_free (mapi_error);
 		g_static_mutex_unlock (&auth_mutex);
@@ -1281,6 +1304,80 @@ ecbm_connect_user (ECalBackend *backend,
 	return E_SOURCE_AUTHENTICATION_ACCEPTED;
 }
 
+static gboolean
+e_cal_backend_mapi_ensure_connected (ECalBackendMAPI *cbma,
+				     GCancellable *cancellable,
+				     GError **perror)
+{
+	CamelMapiSettings *settings;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbma), FALSE);
+
+	if (cbma->priv->conn && e_mapi_connection_connected (cbma->priv->conn))
+		return TRUE;
+
+	settings = ecbm_get_collection_settings (cbma);
+
+	if (!camel_mapi_settings_get_kerberos (settings) ||
+	    ecbm_connect_user (E_CAL_BACKEND (cbma), cancellable, NULL, &local_error) != E_SOURCE_AUTHENTICATION_ACCEPTED) {
+		ESourceRegistry *registry;
+
+		registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbma));
+
+		e_source_registry_authenticate_sync (
+			registry, e_backend_get_source (E_BACKEND (cbma)),
+			E_SOURCE_AUTHENTICATOR (cbma),
+			cancellable, &local_error);
+	}
+
+	if (!local_error)
+		return TRUE;
+
+	g_propagate_error (perror, local_error);
+
+	return FALSE;
+}
+
+static void
+e_cal_backend_mapi_maybe_disconnect (ECalBackendMAPI *cbma,
+				     const GError *mapi_error)
+{
+	g_return_if_fail (E_IS_CAL_BACKEND_MAPI (cbma));
+
+	/* no error or already disconnected */
+	if (!mapi_error || !cbma->priv->conn)
+		return;
+
+	if (g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR) ||
+	    g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_CALL_FAILED)) {
+		e_mapi_connection_disconnect (cbma->priv->conn,
+			!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR),
+			NULL, NULL);
+		g_object_unref (cbma->priv->conn);
+		cbma->priv->conn = NULL;
+	}
+}
+
+static EMapiConnection *
+e_cal_backend_mapi_get_connection (ECalBackendMAPI *cbma,
+				   GCancellable *cancellable,
+				   GError **perror)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbma), NULL);
+	g_return_val_if_fail (cbma->priv != NULL, NULL);
+
+	if (cbma->priv->conn)
+		return cbma->priv->conn;
+
+	if (!e_backend_get_online (E_BACKEND (cbma)))
+		return NULL;
+
+	if (!e_cal_backend_mapi_ensure_connected (cbma, cancellable, perror))
+		return NULL;
+
+	return cbma->priv->conn;
+}
 
 static void
 ecbm_open (ECalBackend *backend,
@@ -1295,7 +1392,6 @@ ecbm_open (ECalBackend *backend,
 	ESourceMapiFolder *ext_mapi_folder;
 	guint64 fid;
 	const gchar *cache_dir;
-	CamelMapiSettings *settings;
 	GError *error = NULL;
 
 	if (e_cal_backend_is_opened (backend)) {
@@ -1306,8 +1402,6 @@ ecbm_open (ECalBackend *backend,
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
 	priv = cbmapi->priv;
 
-	settings = ecbm_get_collection_settings (cbmapi);
-
 	esource = e_backend_get_source (E_BACKEND (cbmapi));
 	ext_mapi_folder = e_source_get_extension (esource, E_SOURCE_EXTENSION_MAPI_FOLDER);
 	fid = e_source_mapi_folder_get_id (ext_mapi_folder);
@@ -1377,17 +1471,7 @@ ecbm_open (ECalBackend *backend,
 	e_cal_backend_notify_online (backend, TRUE);
 	e_cal_backend_notify_readonly (backend, priv->read_only);
 
-	if (!camel_mapi_settings_get_kerberos (settings) ||
-	    ecbm_connect_user (backend, cancellable, NULL, &error) != E_SOURCE_AUTHENTICATION_ACCEPTED) {
-		ESourceRegistry *registry;
-
-		registry = e_cal_backend_get_registry (backend);
-
-		e_source_registry_authenticate_sync (
-			registry, esource,
-			E_SOURCE_AUTHENTICATOR (backend),
-			cancellable, &error);
-	}
+	e_cal_backend_mapi_ensure_connected (cbmapi, cancellable, &error);
 
 	if (error && perror)
 		g_propagate_error (perror, g_error_copy (error));
@@ -1521,37 +1605,45 @@ get_server_data (ECalBackendMAPI *cbmapi,
 		 struct cal_cbdata *cbdata,
 		 GCancellable *cancellable)
 {
-	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	EMapiConnection *conn;
 	icalcomponent *icalcomp;
 	mapi_id_t mid;
 	mapi_object_t obj_folder;
-	GError *error = NULL;
+	GError *mapi_error = NULL;
 
 	icalcomp = e_cal_component_get_icalcomponent (comp);
 	get_comp_mid (icalcomp, &mid);
 
-	if (!ecbm_open_folder (cbmapi, priv->conn, &obj_folder, cancellable, NULL))
-		return;
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+	if (!conn)
+		goto cleanup;
 
-	if (!e_mapi_connection_transfer_object (priv->conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, cancellable, &error)) {
-		if (!g_error_matches (error, E_MAPI_ERROR, MAPI_E_NOT_FOUND)) {
-			g_clear_error (&error);
-			e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, NULL);
-			return;
+	if (!ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error))
+		goto cleanup;
+
+	if (!e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, cancellable, &mapi_error)) {
+		if (!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NOT_FOUND)) {
+			g_clear_error (&mapi_error);
+			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
+			goto cleanup;
 		}
 
 		/* try to find by global-id, if not found by MID */
-		g_clear_error (&error);
+		g_clear_error (&mapi_error);
 	}
 
-	if (e_mapi_connection_list_objects (priv->conn, &obj_folder,
+	if (e_mapi_connection_list_objects (conn, &obj_folder,
 					    ecbm_build_global_id_restriction, comp,
 					    ecbm_list_for_one_mid_cb, &mid,
-					    cancellable, NULL)) {
-		e_mapi_connection_transfer_object (priv->conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, cancellable, NULL);
+					    cancellable, &mapi_error)) {
+		e_mapi_connection_transfer_object (conn, &obj_folder, mid, ecbm_capture_req_props, cbdata, cancellable, &mapi_error);
 	}
 
-	e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, NULL);
+	e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
+
+ cleanup:
+	e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+	g_clear_error (&mapi_error);
 }
 
 /* frees data members allocated in get_server_data(), not the cbdata itself */
@@ -1587,6 +1679,7 @@ ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 {
 	ECalBackendMAPI *cbmapi;
 	ECalBackendMAPIPrivate *priv;
+	EMapiConnection *conn;
 	icalcomponent_kind kind;
 	icalcomponent *icalcomp;
 	ECalComponent *comp;
@@ -1630,7 +1723,8 @@ ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 	e_cal_component_set_last_modified (comp, &current);
 
 	/* Check if object exists */
-	if (e_backend_get_online (E_BACKEND (backend))) {
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+	if (conn) {
 		struct cal_cbdata cbdata = { 0 };
 		gboolean status;
 		mapi_object_t obj_folder;
@@ -1652,18 +1746,18 @@ ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 		cbdata.msgflags = MSGFLAG_READ;
 		cbdata.meeting_type = has_attendees ? MEETING_OBJECT : NOT_A_MEETING;
 		cbdata.resp = has_attendees ? olResponseOrganized : olResponseNone;
-		cbdata.appt_id = e_mapi_cal_util_get_new_appt_id (priv->conn, priv->fid);
+		cbdata.appt_id = e_mapi_cal_util_get_new_appt_id (conn, priv->fid);
 		cbdata.appt_seq = 0;
 		cbdata.globalid = NULL;
 		cbdata.cleanglobalid = NULL;
 
-		status = ecbm_open_folder (cbmapi, priv->conn, &obj_folder, cancellable, &mapi_error);
+		status = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
 		if (status) {
-			e_mapi_connection_create_object (priv->conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
+			e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE,
 							 e_mapi_cal_utils_comp_to_object, &cbdata,
 							 &mid, cancellable, &mapi_error);
 
-			e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, &mapi_error);
+			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 		}
 
 		g_free (cbdata.username);
@@ -1674,6 +1768,7 @@ ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 		if (!mid) {
 			g_object_unref (comp);
 			mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to create item on a server"));
+			e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
 			if (mapi_error)
 				g_error_free (mapi_error);
 			return;
@@ -1691,7 +1786,12 @@ ecbm_create_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 		*new_ecalcomp = e_cal_component_clone (comp);
 		e_cal_backend_notify_component_created (E_CAL_BACKEND (cbmapi), *new_ecalcomp);
 	} else {
-		g_propagate_error (error, EDC_ERROR (UnsupportedMethod));
+		e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+		if (!mapi_error)
+			g_propagate_error (error, EDC_ERROR (RepositoryOffline));
+		else
+			mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
+		g_clear_error (&mapi_error);
 		g_object_unref (comp);
 		return;
 	}
@@ -1760,6 +1860,7 @@ ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 {
 	ECalBackendMAPI *cbmapi;
         ECalBackendMAPIPrivate *priv;
+	EMapiConnection *conn;
 	icalcomponent_kind kind;
 	icalcomponent *icalcomp;
 	ECalComponent *comp, *cache_comp = NULL;
@@ -1821,7 +1922,9 @@ ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 	cbdata.get_timezone = (icaltimezone * (*)(gpointer data, const gchar *tzid)) ecbm_internal_get_timezone;
 	cbdata.get_tz_data = cbmapi;
 
-	if (e_backend_get_online (E_BACKEND (backend))) {
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+
+	if (conn) {
 		gboolean has_attendees = e_cal_component_has_attendees (comp);
 		mapi_object_t obj_folder;
 
@@ -1863,13 +1966,13 @@ ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 			cbdata.meeting_type = has_attendees ? MEETING_OBJECT_RCVD : NOT_A_MEETING;
 		}
 
-		status = ecbm_open_folder (cbmapi, priv->conn, &obj_folder, cancellable, &mapi_error);
+		status = ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &mapi_error);
 		if (status) {
-			status = e_mapi_connection_modify_object (priv->conn, &obj_folder, mid, 
+			status = e_mapi_connection_modify_object (conn, &obj_folder, mid, 
 								  e_mapi_cal_utils_comp_to_object, &cbdata,
 								  cancellable, &mapi_error);
 
-			status = e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, &mapi_error) && status;
+			status = e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error) && status;
 		}
 
 		free_server_data (&cbdata);
@@ -1878,6 +1981,7 @@ ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 			g_object_unref (cache_comp);
 
 			mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to modify item on a server"));
+			e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
 			if (mapi_error)
 				g_error_free (mapi_error);
 			return;
@@ -1885,7 +1989,12 @@ ecbm_modify_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 	} else {
 		g_object_unref (comp);
 		g_object_unref (cache_comp);
-		g_propagate_error (error, EDC_ERROR (UnsupportedMethod));
+		e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+		if (!mapi_error)
+			g_propagate_error (error, EDC_ERROR (RepositoryOffline));
+		else
+			mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
+		g_clear_error (&mapi_error);
 		return;
 	}
 
@@ -1906,10 +2015,11 @@ ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 {
 	ECalBackendMAPI *cbmapi;
         ECalBackendMAPIPrivate *priv;
+	EMapiConnection *conn;
 	icalcomponent *icalcomp;
 	gchar *calobj = NULL;
 	mapi_id_t mid;
-	GError *err = NULL;
+	GError *err = NULL, *mapi_error = NULL;
 
 	*old_ecalcomp = *new_ecalcomp = NULL;
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
@@ -1941,6 +2051,8 @@ ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 
 	get_comp_mid (icalcomp, &mid);
 
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+
 	if (mod == CALOBJ_MOD_THIS && rid && *rid) {
 		gchar *new_calobj = NULL;
 		struct icaltimetype time_rid;
@@ -1951,7 +2063,7 @@ ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 		new_calobj = icalcomponent_as_ical_string_r (icalcomp);
 		ecbm_modify_object (backend, cal, cancellable, new_calobj, CALOBJ_MOD_ALL, old_ecalcomp, new_ecalcomp, &err);
 		g_free (new_calobj);
-	} else {
+	} else if (conn) {
 		mapi_object_t obj_folder;
 		GSList *list=NULL, *l, *comp_list = e_cal_backend_store_get_components_by_uid (priv->store, uid);
 		GError *ri_error = NULL;
@@ -1960,8 +2072,8 @@ ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 		*pmid = mid;
 		list = g_slist_prepend (list, pmid);
 
-		if (ecbm_open_folder (cbmapi, priv->conn, &obj_folder, cancellable, &ri_error)) {
-			if (e_mapi_connection_remove_items (priv->conn, &obj_folder, list, cancellable, &ri_error)) {
+		if (ecbm_open_folder (cbmapi, conn, &obj_folder, cancellable, &ri_error)) {
+			if (e_mapi_connection_remove_items (conn, &obj_folder, list, cancellable, &ri_error)) {
 				for (l = comp_list; l; l = l->next) {
 					ECalComponent *comp = E_CAL_COMPONENT (l->data);
 					ECalComponentId *id = e_cal_component_get_id (comp);
@@ -1974,17 +2086,27 @@ ecbm_remove_object (ECalBackend *backend, EDataCal *cal, GCancellable *cancellab
 				}
 			}
 
-			e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, &ri_error);
+			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &ri_error);
 
 			*old_ecalcomp = e_cal_component_new_from_icalcomponent (icalparser_parse_string (calobj));
 			*new_ecalcomp = NULL;
 			err = NULL; /* Success */
-		} else
-			mapi_error_to_edc_error (&err, ri_error, OtherError, "Cannot remove items from a server");
+		} else {
+			e_cal_backend_mapi_maybe_disconnect (cbmapi, ri_error);
+			mapi_error_to_edc_error (&err, ri_error, OtherError, _("Cannot remove items from a server"));
+		}
 
 		g_slist_free_full (list, g_free);
 		g_slist_free (comp_list);
+	} else {
+		e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
+		if (!mapi_error)
+			g_propagate_error (&err, EDC_ERROR (RepositoryOffline));
+		else
+			mapi_error_to_edc_error (&err, mapi_error, RepositoryOffline, NULL);
+		g_clear_error (&mapi_error);
 	}
+
 	g_free (calobj);
 
 	if (err)
@@ -2001,21 +2123,25 @@ static void
 ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **error)
 {
 	ECalBackendMAPI *cbmapi;
-	ECalBackendMAPIPrivate *priv;
+	EMapiConnection *conn;
 	icalcomponent_kind kind;
 	icalcomponent *icalcomp;
 	GError *mapi_error = NULL;
 
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
-	priv = cbmapi->priv;
 
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
 
 	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), InvalidArg);
 	e_return_data_cal_error_if_fail (calobj != NULL, InvalidArg);
 
-	if (!e_backend_get_online (E_BACKEND (backend))) {
-		g_propagate_error (error, EDC_ERROR (RepositoryOffline));
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+	if (!conn) {
+		if (!mapi_error)
+			g_propagate_error (error, EDC_ERROR (RepositoryOffline));
+		else
+			mapi_error_to_edc_error (error, mapi_error, RepositoryOffline, NULL);
+		g_clear_error (&mapi_error);
 		return;
 	}
 
@@ -2136,12 +2262,12 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
 			cbdata.cleanglobalid = &cleanglobalid;
 
 			mid = 0;
-			if (e_mapi_connection_open_default_folder (priv->conn, olFolderSentMail, &obj_folder, cancellable, &mapi_error)) {
-				e_mapi_connection_create_object (priv->conn, &obj_folder, E_MAPI_CREATE_FLAG_SUBMIT,
+			if (e_mapi_connection_open_default_folder (conn, olFolderSentMail, &obj_folder, cancellable, &mapi_error)) {
+				e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_SUBMIT,
 								 e_mapi_cal_utils_comp_to_object, &cbdata,
 								 &mid, cancellable, &mapi_error);
 
-				e_mapi_connection_close_folder (priv->conn, &obj_folder, cancellable, &mapi_error);
+				e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 			}
 
 			cbdata.globalid = NULL;
@@ -2153,6 +2279,7 @@ ecbm_send_objects (ECalBackend *backend, EDataCal *cal, GCancellable *cancellabl
 			if (!mid) {
 				g_object_unref (comp);
 				mapi_error_to_edc_error (error, mapi_error, OtherError, _("Failed to create item on a server"));
+				e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
 				if (mapi_error)
 					g_error_free (mapi_error);
 				return;
@@ -2386,19 +2513,25 @@ static void
 ecbm_get_free_busy (ECalBackend *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusy, GError **perror)
 {
 	ECalBackendMAPI *cbmapi;
-	ECalBackendMAPIPrivate *priv;
+	EMapiConnection *conn;
 	GError *mapi_error = NULL;
 
 	cbmapi = E_CAL_BACKEND_MAPI (backend);
-	priv = cbmapi->priv;
 
-	if (!priv->conn) {
-		g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
+	conn = e_cal_backend_mapi_get_connection (cbmapi, cancellable, &mapi_error);
+
+	if (!conn) {
+		if (!mapi_error)
+			g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
+		else
+			mapi_error_to_edc_error (perror, mapi_error, RepositoryOffline, NULL);
+		g_clear_error (&mapi_error);
 		return;
 	}
 
-	if (!e_mapi_cal_utils_get_free_busy_data (priv->conn, users, start, end, freebusy, cancellable, &mapi_error)) {
+	if (!e_mapi_cal_utils_get_free_busy_data (conn, users, start, end, freebusy, cancellable, &mapi_error)) {
 		mapi_error_to_edc_error (perror, mapi_error, OtherError, _("Failed to get Free/Busy data"));
+		e_cal_backend_mapi_maybe_disconnect (cbmapi, mapi_error);
 
 		if (mapi_error)
 			g_error_free (mapi_error);
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index 9143077..70fb211 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -407,13 +407,15 @@ e_mapi_connection_dispose (GObject *object)
 static void
 e_mapi_connection_finalize (GObject *object)
 {
+	EMapiConnection *conn;
 	EMapiConnectionPrivate *priv;
 
-	priv = E_MAPI_CONNECTION (object)->priv;
+	conn = E_MAPI_CONNECTION (object);
+	priv = conn->priv;
 
 	if (priv) {
 		LOCK_VOID (NULL, NULL);
-		disconnect (priv, TRUE);
+		disconnect (priv, TRUE && e_mapi_connection_connected (conn));
 		g_free (priv->profile);
 		priv->profile = NULL;
 
@@ -553,7 +555,8 @@ e_mapi_connection_find (const gchar *profile)
 		EMapiConnection *conn = E_MAPI_CONNECTION (l->data);
 		EMapiConnectionPrivate *priv = conn->priv;
 
-		if (priv && priv->profile && g_str_equal (profile, priv->profile))
+		if (priv && priv->profile && g_str_equal (profile, priv->profile) &&
+		    e_mapi_connection_connected (conn))
 			res = conn;
 	}
 
@@ -658,7 +661,7 @@ e_mapi_connection_disconnect (EMapiConnection *conn,
 	LOCK (cancellable, perror, FALSE);
 
 	res = priv->session != NULL;
-	disconnect (priv, clean);
+	disconnect (priv, clean && e_mapi_connection_connected (conn));
 
 	UNLOCK ();
 
@@ -716,15 +719,53 @@ e_mapi_connection_reconnect (EMapiConnection *conn,
 	return priv->session != NULL;
 }
 
+static gboolean
+can_reach_mapi_server (const gchar *server_address,
+		       GCancellable *cancellable,
+		       GError **perror)
+{
+	GNetworkMonitor *network_monitor;
+	GSocketConnectable *connectable;
+	GError *local_error = NULL;
+	gboolean reachable;
+
+	g_return_val_if_fail (server_address != NULL, FALSE);
+
+	network_monitor = g_network_monitor_get_default ();
+	connectable = g_network_address_new (server_address, 135);
+	reachable = g_network_monitor_can_reach (network_monitor, connectable, cancellable, &local_error);
+	g_object_unref (connectable);
+
+	if (!reachable) {
+		if (local_error)
+			g_propagate_error (perror, local_error);
+		else
+			g_set_error (perror, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, _("Server '%s' cannot be reached"), server_address);
+	}
+
+	return reachable;
+}
+
 gboolean
 e_mapi_connection_connected (EMapiConnection *conn)
 {
 	/* to have this used in the below macros */
 	GError **perror = NULL;
+	gboolean res;
 
 	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
 
-	return priv->session != NULL;
+	res = priv->session != NULL;
+	if (res) {
+		struct mapi_profile profile = { 0 };
+
+		if (MAPI_E_SUCCESS == OpenProfile (priv->mapi_ctx, &profile, priv->profile, NULL)) {
+			res = can_reach_mapi_server (profile.server, NULL, perror);
+			ShutDown (&profile);
+		}
+	}
+
+	return res;
 }
 
 static gboolean
@@ -6686,33 +6727,6 @@ try_create_profile (ESourceRegistry *registry,
 	return data.has_profile;
 }
 
-static gboolean
-can_reach_mapi_server (const gchar *server_address,
-		       GCancellable *cancellable,
-		       GError **perror)
-{
-	GNetworkMonitor *network_monitor;
-	GSocketConnectable *connectable;
-	GError *local_error = NULL;
-	gboolean reachable;
-
-	g_return_val_if_fail (server_address != NULL, FALSE);
-
-	network_monitor = g_network_monitor_get_default ();
-	connectable = g_network_address_new (server_address, 135);
-	reachable = g_network_monitor_can_reach (network_monitor, connectable, cancellable, &local_error);
-	g_object_unref (connectable);
-
-	if (!reachable) {
-		if (local_error)
-			g_propagate_error (perror, local_error);
-		else
-			g_set_error (perror, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, _("Server '%s' cannot be reached"), server_address);
-	}
-
-	return reachable;
-}
-
 static struct mapi_session *
 mapi_profile_load (ESourceRegistry *registry,
 		   struct mapi_context *mapi_ctx,



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