[evolution-mapi] Bug #608327 - Cannot recover after connection lost (mailer part)



commit 4f8268749ecb66b129785f1be8edfe854b7728a9
Author: Milan Crha <mcrha redhat com>
Date:   Mon Jul 16 18:00:05 2012 +0200

    Bug #608327 - Cannot recover after connection lost (mailer part)

 configure.ac                                       |    2 +-
 src/camel/camel-mapi-folder.c                      |  160 ++++++++++++--------
 src/camel/camel-mapi-store.c                       |   85 ++++++++---
 src/camel/camel-mapi-store.h                       |   10 +-
 .../e-mapi-subscribe-foreign-folder.c              |    4 +-
 src/libexchangemapi/e-mapi-connection.c            |   66 +++++++--
 src/libexchangemapi/e-mapi-connection.h            |    5 +-
 7 files changed, 233 insertions(+), 99 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 81df317..a5760cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ dnl *******************
 m4_define([eds_minimum_version], [ema_version])
 m4_define([evo_minimum_version], [ema_version])
 m4_define([libmapi_minimum_version], [1.0])
-m4_define([glib_minimum_version], [2.16.1])
+m4_define([glib_minimum_version], [2.32.0])
 m4_define([gtk_minimum_version], [2.99.2])
 
 dnl ***********************************
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index b74d09c..c5d23dd 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -67,17 +67,27 @@ cmf_open_folder (CamelMapiFolder *mapi_folder,
 		 GError **perror)
 {
 	gboolean res;
+	GError *mapi_error = NULL;
 
 	g_return_val_if_fail (mapi_folder != NULL, FALSE);
 	g_return_val_if_fail (conn != NULL, FALSE);
 	g_return_val_if_fail (obj_folder != NULL, FALSE);
 
 	if ((mapi_folder->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)
-		res = e_mapi_connection_open_foreign_folder (conn, mapi_folder->priv->foreign_username, mapi_folder->folder_id, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_foreign_folder (conn, mapi_folder->priv->foreign_username, mapi_folder->folder_id, obj_folder, cancellable, &mapi_error);
 	else if ((mapi_folder->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0)
-		res = e_mapi_connection_open_public_folder (conn, mapi_folder->folder_id, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_public_folder (conn, mapi_folder->folder_id, obj_folder, cancellable, &mapi_error);
 	else
-		res = e_mapi_connection_open_personal_folder (conn, mapi_folder->folder_id, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_personal_folder (conn, mapi_folder->folder_id, obj_folder, cancellable, &mapi_error);
+
+	if (mapi_error) {
+		CamelMapiStore *mapi_store;
+
+		mapi_store = CAMEL_MAPI_STORE (camel_folder_get_parent_store (CAMEL_FOLDER (mapi_folder)));
+		camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+
+		g_propagate_error (perror, mapi_error);
+	}
 
 	return res;
 }
@@ -746,12 +756,12 @@ camel_mapi_folder_fetch_summary (CamelFolder *folder, GCancellable *cancellable,
 	CamelMapiStoreInfo *msi = NULL;
 	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
 	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (folder);
-	EMapiConnection *conn = camel_mapi_store_get_connection (mapi_store);
+	EMapiConnection *conn = camel_mapi_store_get_connection (mapi_store, cancellable, mapi_error);
 	struct FolderBasicPropertiesData fbp;
 	struct GatherChangedObjectsData gco;
 	mapi_object_t obj_folder;
 
-	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+	if (!conn)
 		return FALSE;
 
 	camel_folder_freeze (folder);
@@ -869,6 +879,9 @@ camel_mapi_folder_fetch_summary (CamelFolder *folder, GCancellable *cancellable,
 		msi->last_obj_total = fbp.obj_total;
 	}
 
+	if (mapi_error && *mapi_error)
+		camel_mapi_store_maybe_disconnect (mapi_store, *mapi_error);
+
 	camel_folder_summary_save_to_db (folder->summary, NULL);
 	camel_folder_thaw (folder);
 
@@ -917,7 +930,7 @@ mapi_refresh_folder (CamelFolder *folder, GCancellable *cancellable, GError **er
 		goto end1;
 	}
 
-	if (!camel_mapi_store_connected (mapi_store, &mapi_error)) {
+	if (!camel_mapi_store_connected (mapi_store, cancellable, &mapi_error)) {
 		if (mapi_error) {
 			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 				g_set_error (
@@ -1153,7 +1166,6 @@ mapi_folder_append_message_sync (CamelFolder *folder,
                                  GError **error)
 {
 	CamelMapiStore *mapi_store;
-	CamelOfflineStore *offline;
 	CamelStoreInfo *si;
 	CamelStore *parent_store;
 	mapi_id_t fid = 0, mid = 0;
@@ -1168,7 +1180,6 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 	parent_store = camel_folder_get_parent_store (folder);
 
 	mapi_store = CAMEL_MAPI_STORE (parent_store);
-	offline = CAMEL_OFFLINE_STORE (parent_store);
 
 	/*Reject outbox / sent & trash*/
 	si = camel_store_summary_path (mapi_store->summary, full_name);
@@ -1186,7 +1197,8 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 		return FALSE;
 	}
 
-	if (!camel_offline_store_get_online (offline)) {
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
+	if (!conn) {
 		g_set_error (
 			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 			_("Offline."));
@@ -1197,7 +1209,6 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 	e_mapi_util_mapi_id_from_string (folder_id, &fid);
 
 	/* Convert MIME to Item */
-	conn = camel_mapi_store_get_connection (mapi_store);
 	if (cmf_open_folder (CAMEL_MAPI_FOLDER (folder), conn, &obj_folder, cancellable, &mapi_error)) {
 		struct CamelMapiCreateData cmc;
 
@@ -1215,6 +1226,7 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 		if (mapi_error) {
 			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, mapi_error->message);
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
 			g_error_free (mapi_error);
 		} else {
 			g_set_error (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Offline."));
@@ -1254,7 +1266,10 @@ mapi_folder_expunge_sync (CamelFolder *folder,
 
 	mapi_folder = CAMEL_MAPI_FOLDER (folder);
 	mapi_store = CAMEL_MAPI_STORE (parent_store);
-	conn = camel_mapi_store_get_connection (mapi_store);
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
+
+	if (!conn)
+		return FALSE;
 
 	if ((mapi_folder->camel_folder_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_TRASH) {
 		mapi_object_t obj_folder;
@@ -1296,6 +1311,7 @@ mapi_folder_expunge_sync (CamelFolder *folder,
 				g_set_error (
 					error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 					_("Failed to empty Trash: %s"), mapi_error->message);
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
 			g_error_free (mapi_error);
 		} else {
 			g_set_error_literal (
@@ -1338,11 +1354,17 @@ mapi_folder_expunge_sync (CamelFolder *folder,
 
 	if (deleted_items) {
 		mapi_object_t obj_folder;
+		GError *mapi_error = NULL;
 
-		status = cmf_open_folder (mapi_folder, conn, &obj_folder, cancellable, NULL);
+		status = cmf_open_folder (mapi_folder, conn, &obj_folder, cancellable, &mapi_error);
 		if (status) {
-			status = e_mapi_connection_remove_items (conn, &obj_folder, deleted_items, cancellable, NULL);
-			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, NULL);
+			status = e_mapi_connection_remove_items (conn, &obj_folder, deleted_items, cancellable, &mapi_error);
+			e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
+		}
+
+		if (mapi_error) {
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+			g_clear_error (&mapi_error);
 		}
 
 		if (status) {
@@ -1484,7 +1506,7 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 	}
 
 	/* Check if we are really offline */
-	if (!camel_mapi_store_connected (mapi_store, &mapi_error)) {
+	if (!camel_mapi_store_connected (mapi_store, cancellable, &mapi_error)) {
 		if (mapi_error) {
 			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 				g_set_error (
@@ -1501,9 +1523,11 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 		return NULL;
 	}
 
-	e_mapi_util_mapi_id_from_string (uid, &id_message);
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
+	if (!conn)
+		return NULL;
 
-	conn = camel_mapi_store_get_connection (mapi_store);
+	e_mapi_util_mapi_id_from_string (uid, &id_message);
 
 	success = cmf_open_folder (mapi_folder, conn, &obj_folder, cancellable, &mapi_error);
 	if (success) {
@@ -1518,6 +1542,7 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 				g_set_error (
 					error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_INVALID,
 					_("Could not get message: %s"), mapi_error->message);
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);				
 			g_error_free (mapi_error);
 		} else {
 			g_set_error (
@@ -1568,6 +1593,7 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 	gint i;
 	gboolean is_junk_folder, has_obj_folder = FALSE;
 	mapi_object_t obj_folder;
+	GError *mapi_error = NULL;
 
 	full_name = camel_folder_get_full_name (folder);
 	parent_store = camel_folder_get_parent_store (folder);
@@ -1586,7 +1612,8 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 	folder_id =  camel_mapi_store_folder_id_lookup (mapi_store, full_name);
 	e_mapi_util_mapi_id_from_string (folder_id, &fid);
 
-	if (!camel_mapi_store_connected (mapi_store, error))
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
+	if (!conn)
 		return FALSE;
 
 	is_junk_folder = (mapi_folder->camel_folder_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_JUNK;
@@ -1663,37 +1690,30 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 	   Evo doesnt not take care of it, as I find that scenario to be impractical.
 	*/
 
-	conn = camel_mapi_store_get_connection (mapi_store);
-	has_obj_folder = cmf_open_folder (mapi_folder, conn, &obj_folder, cancellable, NULL);
+	has_obj_folder = cmf_open_folder (mapi_folder, conn, &obj_folder, cancellable, &mapi_error);
 
 	if (read_items && has_obj_folder) {
 		if (read_with_receipt)
-			e_mapi_connection_set_flags (conn, &obj_folder, read_with_receipt, CLEAR_RN_PENDING, cancellable, NULL);
-		e_mapi_connection_set_flags (conn, &obj_folder, read_items, 0, cancellable, NULL);
+			e_mapi_connection_set_flags (conn, &obj_folder, read_with_receipt, CLEAR_RN_PENDING, cancellable, &mapi_error);
+		e_mapi_connection_set_flags (conn, &obj_folder, read_items, 0, cancellable, &mapi_error);
 	}
 
 	if (unread_items && has_obj_folder) {
-		e_mapi_connection_set_flags (conn, &obj_folder, unread_items, CLEAR_READ_FLAG, cancellable, NULL);
+		e_mapi_connection_set_flags (conn, &obj_folder, unread_items, CLEAR_READ_FLAG, cancellable, &mapi_error);
 	}
 
 	/* Remove messages from server*/
 	if (deleted_items && has_obj_folder) {
 		if ((mapi_folder->camel_folder_flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_TRASH) {
-			e_mapi_connection_remove_items (conn, &obj_folder, deleted_items, cancellable, NULL);
+			e_mapi_connection_remove_items (conn, &obj_folder, deleted_items, cancellable, &mapi_error);
 		} else {
-			GError *err = NULL;
 			mapi_id_t deleted_items_fid;
 			mapi_object_t deleted_obj_folder;
 
 			e_mapi_util_mapi_id_from_string (camel_mapi_store_system_folder_fid (mapi_store, olFolderDeletedItems), &deleted_items_fid);
-			if (e_mapi_connection_open_personal_folder (conn, deleted_items_fid, &deleted_obj_folder, cancellable, &err)) {
-				e_mapi_connection_copymove_items (conn, &obj_folder, &deleted_obj_folder, FALSE, deleted_items, cancellable, &err);
-				e_mapi_connection_close_folder (conn, &deleted_obj_folder, cancellable, &err);
-			}
-
-			if (err) {
-				g_warning ("%s: Failed to move deleted items: %s", G_STRFUNC, err->message);
-				g_error_free (err);
+			if (e_mapi_connection_open_personal_folder (conn, deleted_items_fid, &deleted_obj_folder, cancellable, &mapi_error)) {
+				e_mapi_connection_copymove_items (conn, &obj_folder, &deleted_obj_folder, FALSE, deleted_items, cancellable, &mapi_error);
+				e_mapi_connection_close_folder (conn, &deleted_obj_folder, cancellable, &mapi_error);
 			}
 		}
 	}
@@ -1701,27 +1721,21 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 	if (junk_items && has_obj_folder) {
 		mapi_id_t junk_fid = 0;
 		mapi_object_t junk_obj_folder;
-		GError *err = NULL;
 
 		if (has_obj_folder) {
 			e_mapi_util_mapi_id_from_string (camel_mapi_store_system_folder_fid (mapi_store, olFolderJunk), &junk_fid);
-			if (e_mapi_connection_open_personal_folder (conn, junk_fid, &junk_obj_folder, cancellable, &err)) {
-				e_mapi_connection_copymove_items (conn, &obj_folder, &junk_obj_folder, FALSE, junk_items, cancellable, &err);
-				e_mapi_connection_close_folder (conn, &junk_obj_folder, cancellable, &err);
+			if (e_mapi_connection_open_personal_folder (conn, junk_fid, &junk_obj_folder, cancellable, &mapi_error)) {
+				e_mapi_connection_copymove_items (conn, &obj_folder, &junk_obj_folder, FALSE, junk_items, cancellable, &mapi_error);
+				e_mapi_connection_close_folder (conn, &junk_obj_folder, cancellable, &mapi_error);
 			}
 		}
 
 		/* in junk_items are only emails which are not deleted */
 		deleted_items = g_slist_concat (deleted_items, g_slist_copy (junk_items));
-
-		if (err) {
-			g_warning ("%s: Failed to move junk items: %s", G_STRFUNC, err->message);
-			g_error_free (err);
-		}
 	}
 
 	if (has_obj_folder)
-		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, NULL);
+		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 
 	/*Remove messages from local cache*/
 	for (l = deleted_items; l; l = l->next) {
@@ -1752,6 +1766,11 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 	g_slist_foreach (to_free, (GFunc) g_free, NULL);
 	g_slist_free (to_free);
 
+	if (mapi_error) {
+		camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+		g_clear_error (&mapi_error);
+	}
+
 	if (expunge) {
 		/* TODO */
 	}
@@ -1777,7 +1796,7 @@ mapi_folder_transfer_messages_to_sync (CamelFolder *source,
 	gint i = 0;
 	GSList *src_msg_ids = NULL;
 	gboolean success = TRUE;
-	GError *err = NULL;
+	GError *mapi_error = NULL;
 	mapi_object_t src_obj_folder, des_obj_folder;
 	gboolean copymoved = FALSE;
 	EMapiConnection *conn;
@@ -1788,7 +1807,11 @@ mapi_folder_transfer_messages_to_sync (CamelFolder *source,
 			return FALSE;
 	}
 
-	if (!CAMEL_IS_MAPI_FOLDER (source) || !CAMEL_IS_MAPI_FOLDER (destination) ||
+	source_parent_store = camel_folder_get_parent_store (source);
+	mapi_store = CAMEL_MAPI_STORE (source_parent_store);
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
+
+	if (!conn || !CAMEL_IS_MAPI_FOLDER (source) || !CAMEL_IS_MAPI_FOLDER (destination) ||
 	    (CAMEL_MAPI_FOLDER (source)->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0 ||
 	    (CAMEL_MAPI_FOLDER (destination)->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0) {
 		CamelFolderClass *folder_class;
@@ -1801,10 +1824,11 @@ mapi_folder_transfer_messages_to_sync (CamelFolder *source,
 			transferred_uids, cancellable, error);
 	}
 
-	source_parent_store = camel_folder_get_parent_store (source);
+	if (!conn)
+		return FALSE;
+
 	destination_parent_store = camel_folder_get_parent_store (destination);
 
-	mapi_store = CAMEL_MAPI_STORE (source_parent_store);
 	offline = CAMEL_OFFLINE_STORE (destination_parent_store);
 
 	/* check for offline operation */
@@ -1822,23 +1846,22 @@ mapi_folder_transfer_messages_to_sync (CamelFolder *source,
 		src_msg_ids = g_slist_prepend (src_msg_ids, mid);
 	}
 
-	conn = camel_mapi_store_get_connection (mapi_store);
-
-	if (cmf_open_folder (src_mapi_folder, conn, &src_obj_folder, cancellable, &err)) {
-		if (cmf_open_folder (des_mapi_folder, conn, &des_obj_folder, cancellable, &err)) {
-			copymoved = e_mapi_connection_copymove_items (conn, &src_obj_folder, &des_obj_folder, !delete_originals, src_msg_ids, cancellable, &err);
-			e_mapi_connection_close_folder (conn, &des_obj_folder, cancellable, &err);
+	if (cmf_open_folder (src_mapi_folder, conn, &src_obj_folder, cancellable, &mapi_error)) {
+		if (cmf_open_folder (des_mapi_folder, conn, &des_obj_folder, cancellable, &mapi_error)) {
+			copymoved = e_mapi_connection_copymove_items (conn, &src_obj_folder, &des_obj_folder, !delete_originals, src_msg_ids, cancellable, &mapi_error);
+			e_mapi_connection_close_folder (conn, &des_obj_folder, cancellable, &mapi_error);
 		}
 
-		e_mapi_connection_close_folder (conn, &src_obj_folder, cancellable, &err);
+		e_mapi_connection_close_folder (conn, &src_obj_folder, cancellable, &mapi_error);
 	}
 
 	if (!copymoved) {
-		if (!e_mapi_utils_propagate_cancelled_error (err, error))
+		if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 			g_set_error (
 				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-				"%s", err ? err->message : _("Unknown error"));
-		g_clear_error (&err);
+				"%s", mapi_error ? mapi_error->message : _("Unknown error"));
+		camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+		g_clear_error (&mapi_error);
 		success = FALSE;
 	} else if (delete_originals) {
 		changes = camel_folder_change_info_new ();
@@ -1852,7 +1875,7 @@ mapi_folder_transfer_messages_to_sync (CamelFolder *source,
 
 	}
 
-	g_clear_error (&err);
+	g_clear_error (&mapi_error);
 
 	g_slist_foreach (src_msg_ids, (GFunc) g_free, NULL);
 	g_slist_free (src_msg_ids);
@@ -1872,6 +1895,7 @@ mapi_folder_get_quota_info_sync (CamelFolder *folder,
 	CamelMapiStore *mapi_store;
 	CamelFolderQuotaInfo *quota_info = NULL;
 	EMapiConnection *conn;
+	GError *mapi_error = NULL;
 	uint64_t current_size = -1, receive_quota = -1, send_quota = -1;
 
 	g_return_val_if_fail (folder != NULL, NULL);
@@ -1884,11 +1908,11 @@ mapi_folder_get_quota_info_sync (CamelFolder *folder,
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store)))
 		return NULL;
 
-	conn = camel_mapi_store_get_connection (mapi_store);
+	conn = camel_mapi_store_get_connection (mapi_store, cancellable, error);
 	if (conn && e_mapi_connection_get_store_quotas (
 		conn, NULL,
 		&current_size, &receive_quota, &send_quota,
-		cancellable, error)) {
+		cancellable, &mapi_error)) {
 		if (current_size != -1) {
 			if (receive_quota != -1) {
 				quota_info = camel_folder_quota_info_new (_("Receive quota"), current_size, receive_quota);
@@ -1906,9 +1930,19 @@ mapi_folder_get_quota_info_sync (CamelFolder *folder,
 		}
 	}
 
-	if (!quota_info)
-		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-			_("No quota information available"));
+	if (!quota_info) {
+		if (mapi_error) {
+			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
+				g_set_error (
+					error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+					"%s", mapi_error ? mapi_error->message : _("Unknown error"));
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+			g_clear_error (&mapi_error);
+		} else {
+			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+				_("No quota information available"));
+		}
+	}
 
 	return quota_info;
 }
diff --git a/src/camel/camel-mapi-store.c b/src/camel/camel-mapi-store.c
index 9a8eed5..14e7a45 100644
--- a/src/camel/camel-mapi-store.c
+++ b/src/camel/camel-mapi-store.c
@@ -119,6 +119,7 @@ cms_open_folder (CamelMapiStore *mapi_store,
 {
 	CamelStoreInfo *si;
 	CamelMapiStoreInfo *msi;
+	GError *mapi_error = NULL;
 	gboolean res;
 
 	g_return_val_if_fail (mapi_store != NULL, FALSE);
@@ -136,11 +137,16 @@ cms_open_folder (CamelMapiStore *mapi_store,
 	msi = (CamelMapiStoreInfo *) si;
 
 	if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)
-		res = e_mapi_connection_open_foreign_folder (conn, msi->foreign_username, fid, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_foreign_folder (conn, msi->foreign_username, fid, obj_folder, cancellable, &mapi_error);
 	else if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0)
-		res = e_mapi_connection_open_public_folder (conn, fid, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_public_folder (conn, fid, obj_folder, cancellable, &mapi_error);
 	else
-		res = e_mapi_connection_open_personal_folder (conn, fid, obj_folder, cancellable, perror);
+		res = e_mapi_connection_open_personal_folder (conn, fid, obj_folder, cancellable, &mapi_error);
+
+	if (mapi_error) {
+		camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+		g_propagate_error (perror, mapi_error);
+	}
 
 	return res;
 }
@@ -155,6 +161,7 @@ cms_peek_folder_store (CamelMapiStore *mapi_store,
 {
 	CamelStoreInfo *si;
 	CamelMapiStoreInfo *msi;
+	GError *mapi_error = NULL;
 	gboolean res;
 
 	g_return_val_if_fail (mapi_store != NULL, FALSE);
@@ -172,11 +179,16 @@ cms_peek_folder_store (CamelMapiStore *mapi_store,
 	msi = (CamelMapiStoreInfo *) si;
 
 	if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN) != 0)
-		res = e_mapi_connection_peek_store (conn, FALSE, msi->foreign_username, obj_store, cancellable, perror);
+		res = e_mapi_connection_peek_store (conn, FALSE, msi->foreign_username, obj_store, cancellable, &mapi_error);
 	else if ((msi->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) != 0)
-		res = e_mapi_connection_peek_store (conn, TRUE, NULL, obj_store, cancellable, perror);
+		res = e_mapi_connection_peek_store (conn, TRUE, NULL, obj_store, cancellable, &mapi_error);
 	else
-		res = e_mapi_connection_peek_store (conn, FALSE, NULL, obj_store, cancellable, perror);
+		res = e_mapi_connection_peek_store (conn, FALSE, NULL, obj_store, cancellable, &mapi_error);
+
+	if (mapi_error) {
+		camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
+		g_propagate_error (perror, mapi_error);
+	}
 
 	return res;
 }
@@ -463,7 +475,7 @@ mapi_folders_sync (CamelMapiStore *store, guint32 flags, GCancellable *cancellab
 	GHashTable *old_cache_folders;
 	GError *err = NULL;
 
-	if (!camel_mapi_store_connected (store, NULL)) {
+	if (!camel_mapi_store_connected (store, cancellable, NULL)) {
 		g_set_error_literal (
 			error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
 			_("Folder list is not available in offline mode"));
@@ -472,9 +484,10 @@ mapi_folders_sync (CamelMapiStore *store, guint32 flags, GCancellable *cancellab
 
 	status = e_mapi_connection_get_folders_list (priv->conn, &folder_list, camel_mapi_update_operation_progress_cb, NULL, cancellable, &err);
 	if (!status) {
+		camel_mapi_store_maybe_disconnect (store, err);
+
 		g_warning ("Could not get folder list (%s)\n", err ? err->message : "Unknown error");
-		if (err)
-			g_error_free (err);
+		g_clear_error (&err);
 		return TRUE;
 	}
 
@@ -507,8 +520,8 @@ mapi_folders_sync (CamelMapiStore *store, guint32 flags, GCancellable *cancellab
 		if (!status)
 			g_warning ("Could not get Public folder list (%s)\n", err ? err->message : "Unknown error");
 
-		if (err)
-			g_error_free (err);
+		camel_mapi_store_maybe_disconnect (store, err);
+		g_clear_error (&err);
 	}
 
 	temp_list = folder_list;
@@ -1323,6 +1336,7 @@ mapi_store_create_folder_sync (CamelStore *store,
 				g_set_error (
 					error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 					_("Cannot create folder '%s': %s"), folder_name, mapi_error->message);
+			camel_mapi_store_maybe_disconnect (mapi_store, mapi_error);
 			g_error_free (mapi_error);
 		} else {
 			g_set_error (
@@ -1358,7 +1372,7 @@ mapi_store_delete_folder_sync (CamelStore *store,
 		return FALSE;
 	}
 
-	if (!camel_mapi_store_connected ((CamelMapiStore *)store, &local_error)) {
+	if (!camel_mapi_store_connected ((CamelMapiStore *)store, cancellable, &local_error)) {
 		if (local_error != NULL) {
 			g_propagate_error (error, local_error);
 			return FALSE;
@@ -1396,7 +1410,7 @@ mapi_store_delete_folder_sync (CamelStore *store,
 		status = FALSE;
 
 	if (status) {
-		success = mapi_forget_folder (mapi_store, folder_name, error);
+		success = mapi_forget_folder (mapi_store, folder_name, &local_error);
 
 		if (success) {
 			/* remove from name_cache at the end, because the folder_id is from there */
@@ -1404,6 +1418,11 @@ mapi_store_delete_folder_sync (CamelStore *store,
 			g_hash_table_remove (priv->id_hash, folder_id);
 			g_hash_table_remove (priv->name_hash, folder_name);
 		}
+
+		if (local_error) {
+			camel_mapi_store_maybe_disconnect (mapi_store, local_error);
+			g_propagate_error (error, local_error);
+		}
 	} else {
 		success = FALSE;
 
@@ -1414,6 +1433,7 @@ mapi_store_delete_folder_sync (CamelStore *store,
 					_("Cannot remove folder '%s': %s"),
 					folder_name, local_error->message);
 
+			camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 			g_error_free (local_error);
 		} else {
 			g_set_error (
@@ -1454,7 +1474,7 @@ mapi_store_rename_folder_sync (CamelStore *store,
 	service = CAMEL_SERVICE (store);
 	user_cache_dir = camel_service_get_user_cache_dir (service);
 
-	if (!camel_mapi_store_connected ((CamelMapiStore *)store, &local_error)) {
+	if (!camel_mapi_store_connected ((CamelMapiStore *)store, cancellable, &local_error)) {
 		if (local_error != NULL) {
 			g_propagate_error (error, local_error);
 			return FALSE;
@@ -1537,6 +1557,7 @@ mapi_store_rename_folder_sync (CamelStore *store,
 						   The last '%s' is a detailed error message. */
 						_("Cannot rename MAPI folder '%s' to '%s': %s"),
 						old_name, new_name, local_error->message);
+				camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 				g_error_free (local_error);
 			} else {
 				g_set_error (
@@ -1615,6 +1636,7 @@ mapi_store_rename_folder_sync (CamelStore *store,
 							error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 							_("Cannot rename MAPI folder '%s' to '%s': %s"),
 							old_name, new_name, local_error->message);
+					camel_mapi_store_maybe_disconnect (mapi_store, local_error);
 					g_error_free (local_error);
 				} else {
 					g_set_error (
@@ -2095,7 +2117,6 @@ mapi_connect_sync (CamelService *service,
 
 	if (!camel_session_authenticate_sync (session, service, empd.krb_sso ? "MAPIKRB" : NULL, cancellable, error)) {
 		camel_operation_pop_message (cancellable);
-		camel_service_disconnect_sync (service, TRUE, cancellable, NULL);
 		g_free (name);
 		return FALSE;
 	}
@@ -2157,6 +2178,8 @@ mapi_disconnect_sync (CamelService *service,
 		e_mapi_connection_disable_notifications (store->priv->conn, NULL, cancellable, error);
 
 		/* Close the mapi subsystem */
+		e_mapi_connection_disconnect (store->priv->conn, clean, clean ? cancellable : NULL, error);
+
 		g_object_unref (store->priv->conn);
 		store->priv->conn = NULL;
 	}
@@ -2640,10 +2663,29 @@ mapi_build_folder_info (CamelMapiStore *mapi_store, const gchar *parent_name, co
 }
 
 gboolean
-camel_mapi_store_connected (CamelMapiStore *store, GError **error)
+camel_mapi_store_connected (CamelMapiStore *mapi_store,
+			    GCancellable *cancellable,
+			    GError **error)
+{
+	return camel_offline_store_get_online (CAMEL_OFFLINE_STORE (mapi_store))
+	    && camel_service_connect_sync (CAMEL_SERVICE (mapi_store), cancellable, error);
+}
+
+void
+camel_mapi_store_maybe_disconnect (CamelMapiStore *mapi_store,
+				   const GError *mapi_error)
 {
-	return camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))
-	    && camel_service_connect_sync ((CamelService *)store, NULL, error);
+	g_return_if_fail (CAMEL_IS_MAPI_STORE (mapi_store));
+
+	/* no error or already disconnected */
+	if (!mapi_error || !mapi_store->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))
+		camel_service_disconnect_sync (CAMEL_SERVICE (mapi_store),
+			!g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_NETWORK_ERROR),
+			NULL, NULL);
 }
 
 static void
@@ -2775,12 +2817,17 @@ camel_mapi_store_folder_lookup (CamelMapiStore *mapi_store, const gchar *folder_
 }
 
 EMapiConnection *
-camel_mapi_store_get_connection (CamelMapiStore *mapi_store)
+camel_mapi_store_get_connection (CamelMapiStore *mapi_store,
+				 GCancellable *cancellable,
+				 GError **error)
 {
 	g_return_val_if_fail (mapi_store != NULL, NULL);
 	g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), NULL);
 	g_return_val_if_fail (mapi_store->priv != NULL, NULL);
 
+	if (!mapi_store->priv->conn)
+		camel_mapi_store_connected (mapi_store, cancellable, error);
+
 	return mapi_store->priv->conn;
 }
 
diff --git a/src/camel/camel-mapi-store.h b/src/camel/camel-mapi-store.h
index 5eee816..0720c8e 100644
--- a/src/camel/camel-mapi-store.h
+++ b/src/camel/camel-mapi-store.h
@@ -71,14 +71,20 @@ struct _CamelMapiStoreClass {
 };
 
 GType		camel_mapi_store_get_type		(void);
-gboolean	camel_mapi_store_connected		(CamelMapiStore *mapi_store, GError **error);
+gboolean	camel_mapi_store_connected		(CamelMapiStore *mapi_store,
+							 GCancellable *cancellable,
+							 GError **error);
+void		camel_mapi_store_maybe_disconnect	(CamelMapiStore *mapi_store,
+							 const GError *mapi_error);
 
 const gchar *	camel_mapi_store_folder_id_lookup (CamelMapiStore *mapi_store, const gchar *folder_name);
 const gchar *	camel_mapi_store_folder_lookup (CamelMapiStore *mapi_store, const gchar *folder_id);
 const gchar *	camel_mapi_store_system_folder_fid (CamelMapiStore *mapi_store, guint folder_type);
 const gchar *	mapi_folders_hash_table_name_lookup (CamelMapiStore *store, const gchar *fid, gboolean use_cache);
 
-EMapiConnection *	camel_mapi_store_get_connection (CamelMapiStore *mapi_store);
+EMapiConnection *	camel_mapi_store_get_connection (CamelMapiStore *mapi_store,
+							 GCancellable *cancellable,
+							 GError **error);
 
 void		camel_mapi_store_ensure_unique_path (CamelMapiStore *mapi_store, gchar **ppath);
 void		camel_mapi_store_announce_subscribed_folder (CamelMapiStore *mapi_store, const gchar *path);
diff --git a/src/configuration/e-mapi-subscribe-foreign-folder.c b/src/configuration/e-mapi-subscribe-foreign-folder.c
index ff77e62..bd53893 100644
--- a/src/configuration/e-mapi-subscribe-foreign-folder.c
+++ b/src/configuration/e-mapi-subscribe-foreign-folder.c
@@ -292,7 +292,7 @@ check_foreign_folder_thread (GObject *with_object,
 	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
 		return;
 
-	conn = camel_mapi_store_get_connection (CAMEL_MAPI_STORE (with_object));
+	conn = camel_mapi_store_get_connection (CAMEL_MAPI_STORE (with_object), cancellable, perror);
 	if (!conn || !e_mapi_connection_connected (conn)) {
 		make_mapi_error (perror, "EMapiConnection", MAPI_E_NOT_INITIALIZED);
 		return;
@@ -538,7 +538,7 @@ pick_gal_user_clicked_cb (GtkButton *button,
 	text = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
 
 	if (e_mapi_search_gal_user_modal (GTK_WINDOW (dialog),
-					  camel_mapi_store_get_connection (mapi_store),
+					  camel_mapi_store_get_connection (mapi_store, NULL, NULL),
 					  text,
 					  &searched_type,
 					  &display_name,
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index c83954b..9143077 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -283,7 +283,8 @@ release_foreign_stores_cb (gpointer pusername, gpointer pmsg_store, gpointer use
 
 /* should have session_lock locked already, when calling this function */
 static void
-disconnect (EMapiConnectionPrivate *priv)
+disconnect (EMapiConnectionPrivate *priv,
+	    gboolean clean)
 {
 	g_return_if_fail (priv != NULL);
 
@@ -302,9 +303,11 @@ disconnect (EMapiConnectionPrivate *priv)
 	g_hash_table_foreach (priv->foreign_stores, release_foreign_stores_cb, NULL);
 	g_hash_table_remove_all (priv->foreign_stores); 
 
-	Logoff (&priv->msg_store);
-	/* it's released by the Logoff() call
-	mapi_object_release (&priv->msg_store); */
+	if (clean) {
+		Logoff (&priv->msg_store);
+		/* it's released by the Logoff() call
+		mapi_object_release (&priv->msg_store); */
+	}
 
 	if (priv->named_ids)
 		g_hash_table_remove_all (priv->named_ids);
@@ -410,7 +413,7 @@ e_mapi_connection_finalize (GObject *object)
 
 	if (priv) {
 		LOCK_VOID (NULL, NULL);
-		disconnect (priv);
+		disconnect (priv, TRUE);
 		g_free (priv->profile);
 		priv->profile = NULL;
 
@@ -643,18 +646,19 @@ e_mapi_connection_new (ESourceRegistry *registry,
 }
 
 gboolean
-e_mapi_connection_close (EMapiConnection *conn)
+e_mapi_connection_disconnect (EMapiConnection *conn,
+			      gboolean clean,
+			      GCancellable *cancellable,
+			      GError **perror)
 {
 	gboolean res = FALSE;
-	/* to have this used in the below macros */
-	GError **perror = NULL;
 
 	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
 
-	LOCK (NULL, NULL, FALSE);
+	LOCK (cancellable, perror, FALSE);
 
 	res = priv->session != NULL;
-	disconnect (priv);
+	disconnect (priv, clean);
 
 	UNLOCK ();
 
@@ -675,7 +679,7 @@ e_mapi_connection_reconnect (EMapiConnection *conn,
 
 	LOCK (cancellable, perror, FALSE);
 	if (priv->session)
-		e_mapi_connection_close (conn);
+		e_mapi_connection_disconnect (conn, FALSE, cancellable, perror);
 
 	priv->session = mapi_profile_load (priv->registry, priv->mapi_ctx, priv->profile, password ? password->str : NULL, cancellable, perror);
 	if (!priv->session) {
@@ -6682,6 +6686,33 @@ 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,
@@ -6692,6 +6723,7 @@ mapi_profile_load (ESourceRegistry *registry,
 {
 	enum MAPISTATUS	ms = MAPI_E_SUCCESS;
 	struct mapi_session *session = NULL;
+	struct mapi_profile profile = { 0 };
 	guint32 debug_log_level = 0;
 
 	e_return_val_mapi_error_if_fail (mapi_ctx != NULL, MAPI_E_INVALID_PARAMETER, NULL);
@@ -6709,6 +6741,15 @@ mapi_profile_load (ESourceRegistry *registry,
 		SetMAPIDebugLevel (mapi_ctx, debug_log_level);
 	}
 
+	if (MAPI_E_SUCCESS == OpenProfile (mapi_ctx, &profile, profname, NULL)) {
+		if (!can_reach_mapi_server (profile.server, cancellable, perror)) {
+			ShutDown (&profile);
+			goto cleanup;
+		}
+
+		ShutDown (&profile);
+	}
+
 	e_mapi_debug_print("Loading profile %s ", profname);
 
 	ms = MapiLogonEx (mapi_ctx, &session, profname, password);
@@ -6772,6 +6813,9 @@ mapi_profile_create (struct mapi_context *mapi_ctx,
 	e_return_val_mapi_error_if_fail (COMPLETE_PROFILEDATA (empd) && (empd->krb_sso || (empd->password && empd->password->len)),
 					 MAPI_E_INVALID_PARAMETER, FALSE);
 
+	if (!can_reach_mapi_server (empd->server, cancellable, perror))
+		return FALSE;
+
 	if (use_locking) {
 		if (!e_mapi_utils_global_lock (cancellable, perror))
 			return FALSE;
diff --git a/src/libexchangemapi/e-mapi-connection.h b/src/libexchangemapi/e-mapi-connection.h
index 6f63868..0a49273 100644
--- a/src/libexchangemapi/e-mapi-connection.h
+++ b/src/libexchangemapi/e-mapi-connection.h
@@ -241,7 +241,10 @@ gboolean		e_mapi_connection_reconnect		(EMapiConnection *conn,
 								 const GString *password,
 								 GCancellable *cancellable,
 								 GError **perror);
-gboolean		e_mapi_connection_close			(EMapiConnection *conn);
+gboolean		e_mapi_connection_disconnect		(EMapiConnection *conn,
+								 gboolean clean,
+								 GCancellable *cancellable,
+								 GError **perror);
 gboolean		e_mapi_connection_connected		(EMapiConnection *conn);
 
 gboolean		e_mapi_connection_test_foreign_folder	(EMapiConnection *conn,



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