[evolution-data-server/eclient] Changing logic of backend opening phase in favor of e_client_utils_open_new()



commit bfee384189eaffd4f3af32bbefb3ae8b45893fac
Author: Milan Crha <mcrha redhat com>
Date:   Fri May 20 14:42:11 2011 +0200

    Changing logic of backend opening phase in favor of e_client_utils_open_new()

 addressbook/backends/file/e-book-backend-file.c    |    6 +-
 .../backends/google/e-book-backend-google.c        |   43 ++-
 .../backends/groupwise/e-book-backend-groupwise.c  |   35 +-
 addressbook/backends/ldap/e-book-backend-ldap.c    |   86 ++---
 addressbook/backends/vcf/e-book-backend-vcf.c      |    6 +-
 .../backends/webdav/e-book-backend-webdav.c        |   24 +-
 addressbook/libebook/e-book-client-view.c          |    6 +-
 addressbook/libebook/e-book-client.c               |   20 +-
 addressbook/libebook/e-book-view.c                 |    4 +-
 addressbook/libebook/e-book.c                      |    1 +
 addressbook/libedata-book/e-book-backend-sync.c    |   11 +-
 addressbook/libedata-book/e-book-backend-sync.h    |    6 +-
 addressbook/libedata-book/e-book-backend.c         |  271 ++++++++++---
 addressbook/libedata-book/e-book-backend.h         |   17 +-
 addressbook/libedata-book/e-data-book-factory.c    |   12 +-
 addressbook/libedata-book/e-data-book-types.h      |    1 +
 addressbook/libedata-book/e-data-book-view.c       |    2 +-
 addressbook/libedata-book/e-data-book.c            |   85 +++--
 addressbook/libedata-book/e-data-book.h            |    8 +-
 addressbook/libegdbus/e-gdbus-book-view.c          |   44 --
 addressbook/libegdbus/e-gdbus-book-view.h          |    3 -
 addressbook/libegdbus/e-gdbus-book.c               |   62 ++--
 addressbook/libegdbus/e-gdbus-book.h               |   17 +-
 calendar/backends/caldav/e-cal-backend-caldav.c    |   12 +-
 .../backends/contacts/e-cal-backend-contacts.c     |    3 +-
 calendar/backends/file/e-cal-backend-file.c        |   10 +-
 .../backends/groupwise/e-cal-backend-groupwise.c   |   27 +-
 calendar/backends/http/e-cal-backend-http.c        |   29 +-
 calendar/backends/weather/e-cal-backend-weather.c  |    6 +-
 calendar/libecal/e-cal-client-view.c               |    6 +-
 calendar/libecal/e-cal-client.c                    |   20 +-
 calendar/libecal/e-cal-view.c                      |    4 +-
 calendar/libecal/e-cal.c                           |    1 +
 calendar/libedata-cal/e-cal-backend-sync.c         |   12 +-
 calendar/libedata-cal/e-cal-backend-sync.h         |    6 +-
 calendar/libedata-cal/e-cal-backend.c              |  296 ++++++++++++---
 calendar/libedata-cal/e-cal-backend.h              |   17 +-
 calendar/libedata-cal/e-data-cal-factory.c         |   12 +-
 calendar/libedata-cal/e-data-cal-types.h           |    1 +
 calendar/libedata-cal/e-data-cal-view.c            |    2 +-
 calendar/libedata-cal/e-data-cal.c                 |   85 +++--
 calendar/libedata-cal/e-data-cal.h                 |    2 +-
 calendar/libegdbus/e-gdbus-cal-view.c              |   44 --
 calendar/libegdbus/e-gdbus-cal-view.h              |    3 -
 calendar/libegdbus/e-gdbus-cal.c                   |   62 ++--
 calendar/libegdbus/e-gdbus-cal.h                   |   17 +-
 libedataserver/e-client-private.h                  |    1 +
 libedataserver/e-client.c                          |   73 +++-
 libedataserver/e-client.h                          |    4 +-
 libedataserver/e-credentials.h                     |    1 +
 libedataserver/e-gdbus-templates.c                 |   47 +++
 libedataserver/e-gdbus-templates.h                 |   15 +-
 libedataserverui/e-client-utils.c                  |  365 +++++++++++++++++-
 libedataserverui/e-client-utils.h                  |    8 +-
 tests/libebook/client/client-test-utils.c          |    3 +-
 tests/libebook/client/test-client-examine.c        |   10 +-
 tests/libecal/client/test-client-examine.c         |    4 +-
 tests/libedataserverui/Makefile.am                 |    5 +
 tests/libedataserverui/test-client-examine-auth.c  |  418 ++++++++++++++++++++
 59 files changed, 1796 insertions(+), 605 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index ca7cccf..65ca8c3 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -741,7 +741,6 @@ e_book_backend_file_extract_path_from_source (ESource *source)
 
 static void
 e_book_backend_file_authenticate_user (EBookBackendSync *backend,
-				       EDataBook *book,
 				       GCancellable *cancellable,
 				       ECredentials *credentials,
 				       GError **perror)
@@ -1102,10 +1101,9 @@ e_book_backend_file_open (EBookBackendSync       *backend,
 		}
 	}
 
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_set_is_readonly (E_BOOK_BACKEND (backend), readonly);
 	e_book_backend_notify_online (E_BOOK_BACKEND (backend), TRUE);
 	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), readonly);
+	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL /* Success */);
 }
 
 static gboolean
@@ -1212,7 +1210,7 @@ e_book_backend_file_get_backend_property (EBookBackendSync *backend, EDataBook *
 static void
 e_book_backend_file_set_online (EBookBackend *backend, gboolean is_online)
 {
-	if (e_book_backend_is_loaded (backend))
+	if (e_book_backend_is_opened (backend))
 		e_book_backend_notify_online (backend, TRUE);
 }
 
diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c
index f922651..5216f3c 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -1207,7 +1207,7 @@ e_book_backend_google_start_book_view (EBookBackend *backend, EDataBookView *boo
 	if (cache_needs_update (backend, NULL)) {
 		if (!priv->service || !gdata_service_is_authenticated (priv->service)) {
 			/* We need authorization first */
-			e_book_backend_notify_auth_required (backend, NULL);
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
 		} else {
 			/* Update in an idle function, so that this call doesn't block */
 			priv->idle_id = g_idle_add ((GSourceFunc) on_refresh_idle, backend);
@@ -1270,7 +1270,6 @@ proxy_settings_changed (EProxy *proxy, EBookBackend *backend)
 
 typedef struct {
 	EBookBackend *backend;
-	EDataBook *book;
 	guint32 opid;
 } AuthenticateUserData;
 
@@ -1291,37 +1290,37 @@ authenticate_user_cb (GDataService *service, GAsyncResult *result, AuthenticateU
 
 	finish_operation (data->backend, data->opid);
 	e_book_backend_notify_readonly (data->backend, gdata_error ? TRUE : FALSE);
-	e_data_book_respond_authenticate_user (data->book, data->opid, book_error);
+	e_book_backend_notify_opened (data->backend, book_error);
 
-	g_object_unref (data->book);
 	g_object_unref (data->backend);
 	g_slice_free (AuthenticateUserData, data);
 }
 
 static void
-e_book_backend_google_authenticate_user (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, ECredentials *credentials)
+e_book_backend_google_authenticate_user (EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	AuthenticateUserData *data;
+	guint32 opid;
 
 	__debug__ (G_STRFUNC);
 
 	if (!priv->is_online) {
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		return;
 	}
 
 	if (priv->service && gdata_service_is_authenticated (priv->service)) {
 		g_warning ("Connection to Google already established.");
 		e_book_backend_notify_readonly (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, NULL);
+		e_book_backend_notify_opened (backend, NULL);
 		return;
 	}
 
 	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME) || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PASSWORD)) {
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (AUTHENTICATION_FAILED));
+		e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_REQUIRED));
 		return;
 	}
 
@@ -1337,10 +1336,13 @@ e_book_backend_google_authenticate_user (EBookBackend *backend, EDataBook *book,
 		g_signal_connect (priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), backend);
 	}
 
+	opid = -1;
+	while (g_hash_table_lookup (priv->cancellables, GUINT_TO_POINTER (opid)))
+		opid--;
+
 	/* Authenticate with the server asynchronously */
 	data = g_slice_new (AuthenticateUserData);
 	data->backend = g_object_ref (backend);
-	data->book = g_object_ref (book);
 	data->opid = opid;
 
 	cancellable = start_operation (backend, opid, cancellable, _("Authenticating with the serverâ?¦"));
@@ -1367,7 +1369,7 @@ e_book_backend_google_open (EBookBackend *backend, EDataBook *book, guint opid,
 	__debug__ (G_STRFUNC);
 
 	if (priv->cancellables) {
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "Source already loaded!"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Source already loaded!"));
 		return;
 	}
 
@@ -1405,15 +1407,15 @@ e_book_backend_google_open (EBookBackend *backend, EDataBook *book, guint opid,
 	}
 
 	/* Set up ready to be interacted with */
-	e_book_backend_set_is_loaded (backend, TRUE);
-	e_book_backend_set_is_readonly (backend, TRUE);
 	e_book_backend_notify_online (backend, priv->is_online);
 	e_book_backend_notify_readonly (backend, TRUE);
 
 	if (priv->is_online) {
 		/* We're going online, so we need to authenticate and create the service and proxy.
 		 * This is done in e_book_backend_google_authenticate_user() when it gets the authentication data. */
-		e_book_backend_notify_auth_required (backend, NULL);
+		e_book_backend_notify_auth_required (backend, TRUE, NULL);
+	} else {
+		e_book_backend_notify_opened (backend, NULL /* Success */);
 	}
 
 	e_data_book_respond_open (book, opid, NULL /* Success */);
@@ -1570,6 +1572,9 @@ google_cancel_all_operations (EBookBackend *backend)
 
 	__debug__ (G_STRFUNC);
 
+	if (!priv->cancellables)
+		return;
+
 	/* Cancel all active operations */
 	g_hash_table_iter_init (&iter, priv->cancellables);
 	while (g_hash_table_iter_next (&iter, &opid_ptr, (gpointer *) &cancellable)) {
@@ -1590,10 +1595,10 @@ e_book_backend_google_set_online (EBookBackend *backend, gboolean is_online)
 
 	e_book_backend_notify_online (backend, is_online);
 
-	if (is_online) {
+	if (is_online && e_book_backend_is_opened (backend)) {
 		/* Going online, so we need to re-authenticate and re-create the service and proxy.
 		 * This is done in e_book_backend_google_authenticate_user() when it gets the authentication data. */
-		e_book_backend_notify_auth_required (backend, NULL);
+		e_book_backend_notify_auth_required (backend, TRUE, NULL);
 	} else {
 		/* Going offline, so cancel all running operations */
 		google_cancel_all_operations (backend);
@@ -1653,9 +1658,11 @@ e_book_backend_google_finalize (GObject *object)
 
 	__debug__ (G_STRFUNC);
 
-	g_hash_table_destroy (priv->groups_by_id);
-	g_hash_table_destroy (priv->groups_by_name);
-	g_hash_table_destroy (priv->cancellables);
+	if (priv->cancellables) {
+		g_hash_table_destroy (priv->groups_by_id);
+		g_hash_table_destroy (priv->groups_by_name);
+		g_hash_table_destroy (priv->cancellables);
+	}
 
 	G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object);
 }
diff --git a/addressbook/backends/groupwise/e-book-backend-groupwise.c b/addressbook/backends/groupwise/e-book-backend-groupwise.c
index 3ab40fc..414f970 100644
--- a/addressbook/backends/groupwise/e-book-backend-groupwise.c
+++ b/addressbook/backends/groupwise/e-book-backend-groupwise.c
@@ -3130,8 +3130,6 @@ update_address_book_cache (gpointer data)
 
 static void
 e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid,
 					    GCancellable *cancellable,
 					    ECredentials *credentials)
 {
@@ -3163,13 +3161,13 @@ e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
 
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, NULL /* Success */);
 		return;
 	}
 
 	if (priv->cnc) { /*we have already authenticated to server */
 		printf("already authenticated\n");
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, NULL /* Success */);
 		return;
 	}
 
@@ -3182,9 +3180,9 @@ e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
 
 	if (!E_IS_GW_CONNECTION (priv->cnc)) {
 		if (error.status == E_GW_CONNECTION_STATUS_INVALID_PASSWORD)
-			e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (AUTHENTICATION_FAILED));
+			e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED));
 		else
-			e_data_book_respond_authenticate_user (book, opid, EDB_ERROR_FAILED_STATUS (OTHER_ERROR, error.status));
+			e_book_backend_notify_opened (backend, EDB_ERROR_FAILED_STATUS (OTHER_ERROR, error.status));
 		return;
 	}
 
@@ -3198,7 +3196,7 @@ e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
 			status = e_gw_connection_create_book (priv->cnc, priv->book_name,  &id);
 			is_writable = TRUE;
 			if (status != E_GW_CONNECTION_STATUS_OK ) {
-				e_data_book_respond_authenticate_user (book, opid, EDB_ERROR_FAILED_STATUS (OTHER_ERROR, status));
+				e_book_backend_notify_opened (backend, EDB_ERROR_FAILED_STATUS (OTHER_ERROR, status));
 				return;
 			}
 		}
@@ -3206,18 +3204,17 @@ e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
 	if (id != NULL) {
 		priv->container_id = g_strdup (id);
 		g_free (id);
-		e_book_backend_set_is_readonly (backend, !is_writable);
 		e_book_backend_notify_readonly (backend, !is_writable);
 		e_book_backend_notify_online (backend, TRUE);
 		priv->is_readonly = !is_writable;
 		e_gw_connection_get_categories (priv->cnc, &priv->categories_by_id, &priv->categories_by_name);
-		if (!e_gw_connection_get_version (priv->cnc))
-			e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (INVALID_SERVER_VERSION));
-		else
-			e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		/* if (!e_gw_connection_get_version (priv->cnc))
+			/ * error means failure, thus do not send this further * /
+			e_book_backend_notify_opened (backend, EDB_ERROR (INVALID_SERVER_VERSION));
+		else */
+			e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 	} else {
-		e_book_backend_set_is_loaded (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (NO_SUCH_BOOK));
+		e_book_backend_notify_opened (backend, EDB_ERROR (NO_SUCH_BOOK));
 	}
 
 	/* initialize summary file */
@@ -3228,7 +3225,7 @@ e_book_backend_groupwise_authenticate_user (EBookBackend *backend,
 						    SUMMARY_FLUSH_TIMEOUT);
 
 	if (!ebgw->priv->file_db) {
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (OTHER_ERROR));
+		e_book_backend_notify_opened (backend, EDB_ERROR (OTHER_ERROR));
 		return;
 	}
 	if (e_book_backend_db_cache_is_populated (ebgw->priv->file_db)) {
@@ -3496,8 +3493,6 @@ e_book_backend_groupwise_open (EBookBackend	*backend,
 	priv->use_ssl = g_strdup (use_ssl);
 	priv->only_if_exists = only_if_exists;
 
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_set_is_readonly (E_BOOK_BACKEND (backend), TRUE);
 	e_book_backend_notify_readonly (backend, TRUE);
 	e_book_backend_notify_online (backend, priv->is_online);
 
@@ -3523,6 +3518,8 @@ e_book_backend_groupwise_open (EBookBackend	*backend,
 	}*/
 
 	e_data_book_respond_open (book, opid, NULL /* Success */);
+	if (!priv->is_online)
+		e_book_backend_notify_opened (backend, NULL /* Success */);
 }
 
 static void
@@ -3611,7 +3608,7 @@ e_book_backend_groupwise_set_online (EBookBackend *backend, gboolean is_online)
 		printf ("\ne_book_backend_groupwise_set_mode...\n");
 	bg = E_BOOK_BACKEND_GROUPWISE (backend);
 	bg->priv->is_online = is_online;
-	if (e_book_backend_is_loaded (backend)) {
+	if (e_book_backend_is_opened (backend)) {
 		if (!is_online) {
 			e_book_backend_notify_readonly (backend, TRUE);
 			e_book_backend_notify_online (backend, FALSE);
@@ -3622,7 +3619,7 @@ e_book_backend_groupwise_set_online (EBookBackend *backend, gboolean is_online)
 		} else {
 			e_book_backend_notify_readonly (backend, bg->priv->is_readonly);
 			e_book_backend_notify_online (backend, TRUE);
-			e_book_backend_notify_auth_required (backend, NULL);
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
 		}
 	}
 }
diff --git a/addressbook/backends/ldap/e-book-backend-ldap.c b/addressbook/backends/ldap/e-book-backend-ldap.c
index fe68f79..8d2e740 100644
--- a/addressbook/backends/ldap/e-book-backend-ldap.c
+++ b/addressbook/backends/ldap/e-book-backend-ldap.c
@@ -976,7 +976,6 @@ e_book_backend_ldap_connect (EBookBackendLDAP *bl)
 		if (ldap_error == LDAP_SUCCESS
 		    || ldap_error == LDAP_PARTIAL_RESULTS
 		    || LDAP_NAME_ERROR (ldap_error)) {
-			e_book_backend_set_is_loaded (E_BOOK_BACKEND (bl), TRUE);
 			blpriv->connected = TRUE;
 			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
@@ -996,7 +995,7 @@ e_book_backend_ldap_connect (EBookBackendLDAP *bl)
 			}
 			return EDB_ERROR (SUCCESS);
 		} else if (ldap_error == LDAP_UNWILLING_TO_PERFORM) {
-			e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), NULL);
+			e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), TRUE, NULL);
 			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 			return EDB_ERROR (AUTHENTICATION_REQUIRED);
 		} else {
@@ -4729,8 +4728,6 @@ generate_cache (EBookBackendLDAP *book_backend_ldap)
 
 static void
 e_book_backend_ldap_authenticate_user (EBookBackend *backend,
-				       EDataBook    *book,
-				       guint32       opid,
 				       GCancellable *cancellable,
 				       ECredentials *credentials)
 {
@@ -4747,16 +4744,14 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 	if (!bl->priv->is_online) {
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 		return;
 	}
 
 	if (bl->priv->connected) {
 		/* other client connected meanwhile, report success and return */
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 		return;
 	}
@@ -4786,9 +4781,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 				if (!e) {
 					g_warning ("Failed to get the DN for %s", user);
 					ldap_msgfree (res);
-					e_data_book_respond_authenticate_user (book,
-									       opid,
-									       EDB_ERROR (AUTHENTICATION_FAILED));
+					e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED));
 					return;
 				}
 
@@ -4800,11 +4793,8 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 				ldap_memfree (entry_dn);
 				ldap_msgfree (res);
-			}
-			else {
-				e_data_book_respond_authenticate_user (book,
-								       opid,
-								       EDB_ERROR (PERMISSION_DENIED));
+			} else {
+				e_book_backend_notify_opened (backend, EDB_ERROR (PERMISSION_DENIED));
 				return;
 			}
 		}
@@ -4829,7 +4819,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 			error = e_book_backend_ldap_connect (bl);
 			if (error) {
-				e_data_book_respond_authenticate_user (book, opid, error);
+				e_book_backend_notify_opened (backend, error);
 				return;
 			}
 		}
@@ -4851,9 +4841,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 		}
 
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       ldap_error_to_response (ldap_error));
+		e_book_backend_notify_opened (backend, ldap_error_to_response (ldap_error));
 	}
 #ifdef ENABLE_SASL_BINDS
 	else if (!g_ascii_strncasecmp (auth_method, SASL_PREFIX, strlen (SASL_PREFIX))) {
@@ -4866,7 +4854,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 			error = e_book_backend_ldap_connect (bl);
 			if (error) {
-				e_data_book_respond_authenticate_user (book, opid, error);
+				e_book_backend_notify_opened (backend, error);
 				return;
 			}
 		}
@@ -4880,24 +4868,17 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
 		if (ldap_error == LDAP_NOT_SUPPORTED)
-			e_data_book_respond_authenticate_user (book,
-							       opid,
-							       EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
+			e_book_backend_notify_opened (backend, EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
 		else
-			e_data_book_respond_authenticate_user (book,
-							       opid,
-							       ldap_error_to_response (ldap_error));
+			e_book_backend_notify_opened (backend, ldap_error_to_response (ldap_error));
 	}
 #endif
 	else {
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
+		e_book_backend_notify_opened (backend, EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
 		return;
 	}
 
 	if (ldap_error == LDAP_SUCCESS) {
-		e_book_backend_set_is_readonly (backend, FALSE);
 		e_book_backend_notify_readonly (backend, FALSE);
 
 		/* force a requery on the root dse since some ldap
@@ -4915,8 +4896,6 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 				g_warning ("Failed to perform root dse query after authenticating, (ldap_error 0x%02x)", ldap_error);
 		}
 
-		e_data_book_report_readonly (book, FALSE);
-
 		if (bl->priv->marked_for_offline && bl->priv->cache)
 			generate_cache (bl);
 	}
@@ -5018,7 +4997,7 @@ e_book_backend_ldap_open (EBookBackend	*backend,
 		if (enable_debug)
 			printf ("%s ... failed to parse the ldap URI %s\n", G_STRFUNC, uri);
 		g_free (uri);
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "Failed to parse LDAP URI"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Failed to parse LDAP URI"));
 		return;
 	}
 
@@ -5036,26 +5015,23 @@ e_book_backend_ldap_open (EBookBackend	*backend,
 	if (!bl->priv->is_online) {
 		/* Offline */
 
-		e_book_backend_set_is_loaded (backend, TRUE);
-		e_book_backend_set_is_readonly (backend, TRUE);
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
 
 		if (!bl->priv->marked_for_offline) {
-			e_data_book_respond_open (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
+			e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 			return;
 		}
 
 #if 0
 		if (!e_book_backend_cache_is_populated (bl->priv->cache)) {
-			e_data_book_respond_open (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
+			e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 			return;
 		}
 #endif
-		e_data_book_respond_open (book, opid, NULL /* Success */);
+		e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 		return;
 	} else {
-		e_book_backend_set_is_readonly (backend, FALSE);
 		e_book_backend_notify_readonly (backend, FALSE);
 		e_book_backend_notify_online (backend, TRUE);
 	}
@@ -5068,10 +5044,11 @@ e_book_backend_ldap_open (EBookBackend	*backend,
 		if (enable_debug)
 			printf ("%s ... skipping anonymous bind, because auth required\n", G_STRFUNC);
 
-		if (!e_book_backend_is_loaded (backend))
-			e_book_backend_notify_auth_required (backend, NULL);
-		e_book_backend_set_is_loaded (backend, TRUE);
-		e_data_book_respond_open (book, opid, NULL /* Success */);
+		if (!e_book_backend_is_opened (backend))
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
+		else
+			e_book_backend_notify_opened (backend, NULL);
+		e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 		return;
 	}
 
@@ -5080,12 +5057,12 @@ e_book_backend_ldap_open (EBookBackend	*backend,
 	if (err) {
 		if (enable_debug)
 			printf ("%s ... failed to connect to server \n", G_STRFUNC);
-		e_data_book_respond_open (book, opid, err);
+		e_book_backend_respond_opened (backend, book, opid, err);
 		return;
 	}
 
-	if (auth_required && !e_book_backend_is_loaded (backend)) {
-		e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), NULL);
+	if (auth_required && !e_book_backend_is_opened (backend)) {
+		e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), TRUE, NULL);
 		e_data_book_respond_open (book, opid, NULL /* Success */);
 		return;
 	}
@@ -5093,7 +5070,7 @@ e_book_backend_ldap_open (EBookBackend	*backend,
 	if (bl->priv->marked_for_offline)
 		generate_cache (bl);
 
-	e_data_book_respond_open (book, opid, NULL /* Success */);
+	e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 }
 
 static void
@@ -5217,7 +5194,6 @@ e_book_backend_ldap_set_online (EBookBackend *backend, gboolean is_online)
 	if (!is_online) {
 		/* Go offline */
 
-		e_book_backend_set_is_readonly (backend, TRUE);
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
 
@@ -5233,21 +5209,20 @@ e_book_backend_ldap_set_online (EBookBackend *backend, gboolean is_online)
 		bl->priv->connected = FALSE;
 
 #if 0
-		if (e_book_backend_is_loaded (backend))
+		if (e_book_backend_is_opened (backend))
 			start_views (backend);
 #endif
 	} else {
 		/* Go online */
 
-		e_book_backend_set_is_readonly (backend, FALSE);
 		e_book_backend_notify_readonly (backend, FALSE);
 		e_book_backend_notify_online (backend, TRUE);
 
-		if (e_book_backend_is_loaded (backend)) {
+		if (e_book_backend_is_opened (backend)) {
 			GError *error;
 
 			error = e_book_backend_ldap_connect (bl);
-			e_book_backend_notify_auth_required (backend, NULL);
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
 
 			if (error)
 				g_error_free (error);
@@ -5329,6 +5304,11 @@ e_book_backend_ldap_dispose (GObject *object)
 			bl->priv->summary = NULL;
 		}
 
+		if (bl->priv->cache) {
+			g_object_unref (bl->priv->cache);
+			bl->priv->cache = NULL;
+		}
+
 		g_free (bl->priv->ldap_host);
 		g_free (bl->priv->ldap_rootdn);
 		g_free (bl->priv->ldap_search_filter);
diff --git a/addressbook/backends/vcf/e-book-backend-vcf.c b/addressbook/backends/vcf/e-book-backend-vcf.c
index a06bf00..ea235db 100644
--- a/addressbook/backends/vcf/e-book-backend-vcf.c
+++ b/addressbook/backends/vcf/e-book-backend-vcf.c
@@ -541,7 +541,6 @@ e_book_backend_vcf_extract_path_from_uri (const gchar *uri)
 
 static void
 e_book_backend_vcf_authenticate_user (EBookBackendSync *backend,
-				      EDataBook *book,
 				      GCancellable *cancellable,
 				      ECredentials *credentials,
 				      GError **perror)
@@ -628,10 +627,9 @@ e_book_backend_vcf_open (EBookBackendSync        *backend,
 
 	load_file (bvcf, fd);
 
-	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
-	e_book_backend_set_is_readonly (E_BOOK_BACKEND (backend), readonly);
 	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), readonly);
 	e_book_backend_notify_online (E_BOOK_BACKEND (backend), TRUE);
+	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL);
 
 	g_free (uri);
 }
@@ -671,7 +669,7 @@ e_book_backend_vcf_get_backend_property (EBookBackendSync *backend, EDataBook *b
 static void
 e_book_backend_vcf_set_online (EBookBackend *backend, gboolean is_online)
 {
-	if (e_book_backend_is_loaded (backend))
+	if (e_book_backend_is_opened (backend))
 		e_book_backend_notify_online (backend, TRUE);
 }
 
diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c b/addressbook/backends/webdav/e-book-backend-webdav.c
index 7c04eb4..14086e3 100644
--- a/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -1094,7 +1094,7 @@ e_book_backend_webdav_get_contact_list (EBookBackend *backend, EDataBook *book,
 }
 
 static void
-e_book_backend_webdav_authenticate_user (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, ECredentials *credentials)
+e_book_backend_webdav_authenticate_user (EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
@@ -1116,9 +1116,9 @@ e_book_backend_webdav_authenticate_user (EBookBackend *backend, EDataBook *book,
 		e_credentials_util_safe_free_string (priv->password);
 		priv->password = NULL;
 
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (AUTHENTICATION_FAILED));
+		e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED));
 	} else {
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 	}
 }
 
@@ -1176,7 +1176,7 @@ e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid,
 
 	uri = e_source_get_uri (source);
 	if (uri == NULL) {
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "No uri given for addressbook"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "No uri given for addressbook"));
 		return;
 	}
 
@@ -1184,7 +1184,7 @@ e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid,
 	g_free (uri);
 
 	if (!suri) {
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "Invalid uri given for addressbook"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Invalid uri given for addressbook"));
 		return;
 	}
 
@@ -1194,14 +1194,14 @@ e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid,
 
 	if (!priv->is_online && !priv->marked_for_offline ) {
 		soup_uri_free (suri);
-		e_data_book_respond_open (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 		return;
 	}
 
 	if (!suri->scheme || !g_str_equal (suri->scheme, "webdav")) {
 		/* the book is not for us */
 		soup_uri_free (suri);
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "Not a webdav uri"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Not a webdav uri"));
 		return;
 	}
 
@@ -1242,7 +1242,7 @@ e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid,
 	priv->uri = soup_uri_to_string (suri, FALSE);
 	if (!priv->uri) {
 		soup_uri_free (suri);
-		e_data_book_respond_open (book, opid, EDB_ERROR_EX (OTHER_ERROR, "Cannot transform SoupURI to string"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Cannot transform SoupURI to string"));
 		return;
 	}
 
@@ -1261,10 +1261,8 @@ e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid,
 	proxy_settings_changed (priv->proxy, priv);
 	webdav_debug_setup (priv->session);
 
-	e_book_backend_notify_auth_required (backend, NULL);
-	e_book_backend_set_is_loaded (backend, TRUE);
+	e_book_backend_notify_auth_required (backend, TRUE, NULL);
 	e_book_backend_notify_online (backend, TRUE);
-	e_book_backend_set_is_readonly (backend, FALSE);
 	e_book_backend_notify_readonly (backend, FALSE);
 
 	soup_uri_free (suri);
@@ -1286,15 +1284,13 @@ e_book_backend_webdav_set_online (EBookBackend *backend, gboolean is_online)
 	webdav->priv->is_online = is_online;
 
 	/* set_mode is called before the backend is loaded */
-	if (!e_book_backend_is_loaded (backend))
+	if (!e_book_backend_is_opened (backend))
 		return;
 
 	if (!is_online) {
-		e_book_backend_set_is_readonly (backend, TRUE);
 		e_book_backend_notify_readonly (backend, TRUE);
 		e_book_backend_notify_online (backend, FALSE);
 	} else {
-		e_book_backend_set_is_readonly (backend, FALSE);
 		e_book_backend_notify_readonly (backend, FALSE);
 		e_book_backend_notify_online (backend, TRUE);
 	}
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
index 86ce7d7..28ecd89 100644
--- a/addressbook/libebook/e-book-client-view.c
+++ b/addressbook/libebook/e-book-client-view.c
@@ -126,12 +126,12 @@ progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookC
 static void
 complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookClientView *view)
 {
-	GError *error;
+	GError *error = NULL;
 
 	if (!view->priv->running)
 		return;
 
-	error = e_gdbus_book_view_decode_error (in_error_strv);
+	g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
 
 	g_signal_emit (view, signals[COMPLETE], 0, error);
 
@@ -256,7 +256,7 @@ e_book_client_view_stop (EBookClientView *view, GError **error)
  *
  * Client can instruct server to which fields it is interested in only, thus
  * the server can return less data over the wire. The server can still return
- * complete objects, this is just a hint to it that the listef fields will
+ * complete objects, this is just a hint to it that the listed fields will
  * be used only. The UID field is returned always. Initial views has no restriction,
  * and using %NULL for @only_fields will unset any previous changes.
  **/
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index 3fa86b8..c8fea3b 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -63,7 +63,7 @@ G_DEFINE_TYPE (EBookClient, e_book_client, E_TYPE_CLIENT)
  *   Use e_client_util_parse_comma_strings() to parse returned string value
  *   into a #GSList.
  *
- * See also: @CLIENT_BACKEND_PROPERTY_LOADED,
+ * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
  *   @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
  *   @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
  **/
@@ -124,6 +124,7 @@ unwrap_dbus_error (GError *error, GError **client_error)
 		{ err ("OfflineUnavailable",			E_BOOK_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
 		{ err ("NoSpace",				E_BOOK_CLIENT_ERROR_NO_SPACE) }
 	}, cl_errors[] = {
+		{ err ("Busy",					E_CLIENT_ERROR_BUSY) },
 		{ err ("RepositoryOffline",			E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_CLIENT_ERROR_PERMISSION_DENIED) },
 		{ err ("AuthenticationFailed",			E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
@@ -364,6 +365,22 @@ auth_required_cb (EGdbusBook *object, const gchar * const *credentials_strv, EBo
 	e_credentials_free (credentials);
 }
 
+static void
+opened_cb (EGdbusBook *object, const gchar * const *error_strv, EBookClient *client)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+	g_return_if_fail (error_strv != NULL);
+	g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
+
+	e_client_emit_opened (E_CLIENT (client), error);
+
+	if (error)
+		g_error_free (error);
+}
+
 /**
  * e_book_client_new:
  * @source: An #ESource pointer
@@ -463,6 +480,7 @@ e_book_client_new (ESource *source, GError **error)
 	g_signal_connect (client->priv->gdbus_book, "readonly", G_CALLBACK (readonly_cb), client);
 	g_signal_connect (client->priv->gdbus_book, "online", G_CALLBACK (online_cb), client);
 	g_signal_connect (client->priv->gdbus_book, "auth-required", G_CALLBACK (auth_required_cb), client);
+	g_signal_connect (client->priv->gdbus_book, "opened", G_CALLBACK (opened_cb), client);
 
 	return client;
 }
diff --git a/addressbook/libebook/e-book-view.c b/addressbook/libebook/e-book-view.c
index dd88218..877a069 100644
--- a/addressbook/libebook/e-book-view.c
+++ b/addressbook/libebook/e-book-view.c
@@ -124,13 +124,13 @@ progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookV
 static void
 complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookView *book_view)
 {
-	GError *error;
+	GError *error = NULL;
 	EBookViewStatus bv_status = E_BOOK_VIEW_ERROR_OTHER_ERROR;
 
 	if (!book_view->priv->running)
 		return;
 
-	error = e_gdbus_book_view_decode_error (in_error_strv);
+	g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
 
 	switch (error ? error->code : E_DATA_BOOK_STATUS_SUCCESS) {
 	case E_DATA_BOOK_STATUS_SUCCESS:
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index a94106e..7969d2b 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -3632,6 +3632,7 @@ get_status_from_error (GError *error)
 		EBookStatus err_code;
 	} errors[] = {
 		{ err ("Success",				E_BOOK_ERROR_OK) },
+		{ err ("Busy",					E_BOOK_ERROR_BUSY) },
 		{ err ("RepositoryOffline",			E_BOOK_ERROR_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_BOOK_ERROR_PERMISSION_DENIED) },
 		{ err ("ContactNotFound",			E_BOOK_ERROR_CONTACT_NOT_FOUND) },
diff --git a/addressbook/libedata-book/e-book-backend-sync.c b/addressbook/libedata-book/e-book-backend-sync.c
index ce3072d..340636c 100644
--- a/addressbook/libedata-book/e-book-backend-sync.c
+++ b/addressbook/libedata-book/e-book-backend-sync.c
@@ -285,7 +285,6 @@ e_book_backend_sync_get_contact_list (EBookBackendSync *backend,
 /**
  * e_book_backend_sync_authenticate_user:
  * @backend: an #EBookBackendSync
- * @book: an #EDataBook
  * @cancellable: a #GCancellable for the operation
  * @credentials: an #ECredentials to authenticate with
  * @error: #GError to set, when something fails
@@ -294,17 +293,15 @@ e_book_backend_sync_get_contact_list (EBookBackendSync *backend,
  **/
 void
 e_book_backend_sync_authenticate_user (EBookBackendSync *backend,
-				       EDataBook *book,
 				       GCancellable *cancellable,
 				       ECredentials *credentials,
 				       GError **error)
 {
 	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (credentials, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync) (backend, book, cancellable, credentials, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync) (backend, cancellable, credentials, error);
 }
 
 static void
@@ -453,16 +450,14 @@ book_backend_get_contact_list (EBookBackend *backend,
 
 static void
 book_backend_authenticate_user (EBookBackend *backend,
-				EDataBook    *book,
-				guint32       opid,
 				GCancellable *cancellable,
 				ECredentials *credentials)
 {
 	GError *error = NULL;
 
-	e_book_backend_sync_authenticate_user (E_BOOK_BACKEND_SYNC (backend), book, cancellable, credentials, &error);
+	e_book_backend_sync_authenticate_user (E_BOOK_BACKEND_SYNC (backend), cancellable, credentials, &error);
 
-	e_data_book_respond_authenticate_user (book, opid, error);
+	e_book_backend_notify_opened (backend, error);
 }
 
 static gboolean
diff --git a/addressbook/libedata-book/e-book-backend-sync.h b/addressbook/libedata-book/e-book-backend-sync.h
index a50f24f..e944052 100644
--- a/addressbook/libedata-book/e-book-backend-sync.h
+++ b/addressbook/libedata-book/e-book-backend-sync.h
@@ -30,7 +30,6 @@ struct _EBookBackendSyncClass {
 
 	/* Virtual methods */
 	void (*open_sync)			(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, gboolean only_if_exists, GError **error);
-	void (*authenticate_user_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, ECredentials *credentials, GError **error);
 	void (*remove_sync)			(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
 	gboolean (*get_backend_property_sync)	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
 	gboolean (*set_backend_property_sync)	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
@@ -39,6 +38,8 @@ struct _EBookBackendSyncClass {
 	void (*modify_contact_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *vcard, EContact **contact, GError **error);
 	void (*get_contact_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *id, gchar **vcard, GError **error);
 	void (*get_contact_list_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *query, GSList **contacts, GError **error);
+
+	void (*authenticate_user_sync)		(EBookBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 };
 
 GType		e_book_backend_sync_get_type		(void);
@@ -46,7 +47,6 @@ GType		e_book_backend_sync_get_type		(void);
 gboolean	e_book_backend_sync_construct		(EBookBackendSync *backend);
 
 void		e_book_backend_sync_open		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, gboolean only_if_exists, GError **error);
-void		e_book_backend_sync_authenticate_user	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, ECredentials *credentials, GError **error);
 void		e_book_backend_sync_remove		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
 gboolean	e_book_backend_sync_get_backend_property(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
 gboolean	e_book_backend_sync_set_backend_property(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
@@ -56,6 +56,8 @@ void		e_book_backend_sync_modify_contact	(EBookBackendSync *backend, EDataBook *
 void		e_book_backend_sync_get_contact		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *id, gchar **vcard, GError **error);
 void		e_book_backend_sync_get_contact_list	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *query, GSList **contacts, GError **error);
 
+void		e_book_backend_sync_authenticate_user	(EBookBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
+
 G_END_DECLS
 
 #endif /* __E_BOOK_BACKEND_SYNC_H__ */
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index 54b5cd9..d261be4 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -16,12 +16,14 @@
 #include "e-data-book.h"
 #include "e-book-backend.h"
 
+#define EDB_OPENING_ERROR e_data_book_create_error (E_DATA_BOOK_STATUS_BUSY, _("Cannot process, book backend is opening"))
+
 struct _EBookBackendPrivate {
 	GMutex *clients_mutex;
 	GSList *clients;
 
 	ESource *source;
-	gboolean loaded, readonly, removed, online;
+	gboolean opening, opened, readonly, removed, online;
 
 	GMutex *views_mutex;
 	GSList *views;
@@ -77,8 +79,10 @@ book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint
 	g_return_if_fail (book != NULL);
 	g_return_if_fail (prop_name != NULL);
 
-	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_LOADED)) {
-		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_loaded (backend) ? "TRUE" : "FALSE");
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_opened (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_opening (backend) ? "TRUE" : "FALSE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
 		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_online (backend) ? "TRUE" : "FALSE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
@@ -292,8 +296,51 @@ e_book_backend_get_source (EBookBackend *backend)
  * @only_if_exists: %TRUE to prevent the creation of a new book
  *
  * Executes an 'open' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_open().
+ * using @backend. This call might be finished
+ * with e_data_book_respond_open() or e_book_backend_respond_opened(),
+ * though the overall opening phase finishes only after call
+ * of e_book_backend_notify_opened() after which call the backend
+ * is either fully opened (including authentication against (remote)
+ * server/storage) or an error was encountered during this opening phase.
+ * 'opened' and 'opening' properties are updated automatically.
+ * The backend refuses all other operations until the opening phase is finished.
+ *
+ * The e_book_backend_notify_opened() is called either from this function
+ * or from e_book_backend_authenticate_user(), or after necessary steps
+ * initiated by these two functions.
+ *
+ * The opening phase usually works like this:
+ * 1) client requests open for the backend
+ * 2) server receives this request and calls e_book_backend_open() - the opening phase begun
+ * 3) either the backend is opened during this call, and notifies client
+ *    with e_book_backend_notify_opened() about that. This is usually
+ *    for local backends; their opening phase is finished
+ * 4) or the backend requires authentication, thus it notifies client
+ *    about that with e_book_backend_notify_auth_required() and is
+ *    waiting for credentials, which will be received from client
+ *    by e_book_backend_authenticate_user() call. Backend's opening
+ *    phase is still running in this case, thus it doesn't call
+ *    e_book_backend_notify_opened() within e_book_backend_open() call.
+ * 5) when backend receives credentials in e_book_backend_authenticate_user()
+ *    then it tries to authenticate against a server/storage with them
+ *    and only after it knows result of the authentication, whether user
+ *    was or wasn't authenticated, it notifies client with the result
+ *    by e_book_backend_notify_opened() and it's opening phase is
+ *    finished now. If there was no error returned then the backend is
+ *    considered opened, otherwise it's considered closed. Use AuthenticationFailed
+ *    error when the given credentials were rejected by the server/store, which
+ *    will result in a re-prompt on the client side, otherwise use AuthenticationRequired
+ *    if there was anything wrong with the given credentials. Set error's
+ *    message to a reason for a re-prompt, it'll be shown to a user.
+ * 6) client checks error returned from e_book_backend_notify_opened() and
+ *    reprompts for a password if it was AuthenticationFailed. Otherwise
+ *    considers backend opened based on the error presence (no error means success).
+ *
+ * In any case, the call of e_book_backend_open() should be always finished
+ * with e_data_book_respond_open(), which has no influence on the opening phase,
+ * or alternatively with e_book_backend_respond_opened(). Never use authentication
+ * errors in e_data_book_respond_open() to notify the client the authentication is
+ * required, there is e_book_backend_notify_auth_required() for this.
  **/
 void
 e_book_backend_open (EBookBackend *backend,
@@ -305,15 +352,25 @@ e_book_backend_open (EBookBackend *backend,
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 
-	if (backend->priv->loaded) {
+	g_mutex_lock (backend->priv->clients_mutex);
+
+	if (e_book_backend_is_opened (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
+
 		e_data_book_report_readonly (book, backend->priv->readonly);
 		e_data_book_report_online (book, backend->priv->online);
 
-		e_data_book_respond_open (book, opid, NULL);
+		e_book_backend_respond_opened (backend, book, opid, NULL);
+	} else if (e_book_backend_is_opening (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
+
+		e_data_book_respond_open (book, opid, EDB_OPENING_ERROR);
 	} else {
 		ESource *source = e_data_book_get_source (book);
 
-		g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+		backend->priv->opening = TRUE;
+		g_mutex_unlock (backend->priv->clients_mutex);
+
 		g_return_if_fail (source != NULL);
 
 		/* Subclasses may need to call e_book_backend_get_cache_dir() in
@@ -349,7 +406,10 @@ e_book_backend_remove (EBookBackend *backend,
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->remove);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->remove) (backend, book, opid, cancellable);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_remove (book, opid, EDB_OPENING_ERROR);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->remove) (backend, book, opid, cancellable);
 }
 
 /**
@@ -376,7 +436,10 @@ e_book_backend_create_contact (EBookBackend *backend,
 	g_return_if_fail (vcard);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->create_contact);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->create_contact) (backend, book, opid, cancellable, vcard);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_create (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->create_contact) (backend, book, opid, cancellable, vcard);
 }
 
 /**
@@ -403,7 +466,10 @@ e_book_backend_remove_contacts (EBookBackend *backend,
 	g_return_if_fail (id_list);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, opid, cancellable, id_list);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_remove_contacts (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, opid, cancellable, id_list);
 }
 
 /**
@@ -430,7 +496,10 @@ e_book_backend_modify_contact (EBookBackend *backend,
 	g_return_if_fail (vcard);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact) (backend, book, opid, cancellable, vcard);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_modify (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact) (backend, book, opid, cancellable, vcard);
 }
 
 /**
@@ -457,7 +526,10 @@ e_book_backend_get_contact (EBookBackend *backend,
 	g_return_if_fail (id);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, opid, cancellable, id);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_get_contact (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, opid, cancellable, id);
 }
 
 /**
@@ -484,7 +556,10 @@ e_book_backend_get_contact_list (EBookBackend *backend,
 	g_return_if_fail (query);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, opid, cancellable, query);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_get_contact_list (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, opid, cancellable, query);
 }
 
 /**
@@ -528,28 +603,32 @@ e_book_backend_stop_book_view (EBookBackend  *backend,
 /**
  * e_book_backend_authenticate_user:
  * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
  * @cancellable: a #GCancellable for the operation
  * @credentials: #ECredentials to use for authentication
  *
- * Executes an 'authenticate' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_authenticate_user().
+ * Notifies @backend about @credentials provided by user to use
+ * for authentication. This notification is usually called during
+ * opening phase as a response to e_book_backend_notify_auth_required()
+ * on the client side and it results in setting property 'opening' to %TRUE
+ * unless the backend is already opened. This function finishes opening
+ * phase, thus it should be finished with e_book_backend_notify_opened().
+ *
+ * See information at e_book_backend_open() for more details
+ * how the opening phase works.
  **/
 void
 e_book_backend_authenticate_user (EBookBackend *backend,
-				  EDataBook    *book,
-				  guint32       opid,
 				  GCancellable *cancellable,
 				  ECredentials *credentials)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (credentials != NULL);
 	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, book, opid, cancellable, credentials);
+	if (backend->priv->opened)
+		backend->priv->opening = TRUE;
+
+	(* E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
 }
 
 static void
@@ -748,7 +827,7 @@ e_book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, gui
  *
  * Checks if @backend's storage is online.
  *
- * Returns: %TRUE if loaded, %FALSE otherwise.
+ * Returns: %TRUE if online, %FALSE otherwise.
  **/
 gboolean
 e_book_backend_is_online (EBookBackend *backend)
@@ -759,36 +838,43 @@ e_book_backend_is_online (EBookBackend *backend)
 }
 
 /**
- * e_book_backend_is_loaded:
+ * e_book_backend_is_opened:
  * @backend: an #EBookBackend
  *
- * Checks if @backend's storage has been opened and the backend
- * itself is ready for accessing.
+ * Checks if @backend's storage has been opened (and
+ * authenticated, if necessary) and the backend itself
+ * is ready for accessing. This property is changed automatically
+ * within call of e_book_backend_notify_opened().
  *
- * Returns: %TRUE if loaded, %FALSE otherwise.
+ * Returns: %TRUE if fully opened, %FALSE otherwise.
  **/
 gboolean
-e_book_backend_is_loaded (EBookBackend *backend)
+e_book_backend_is_opened (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	return backend->priv->loaded;
+	return backend->priv->opened;
 }
 
 /**
- * e_book_backend_set_is_loaded:
+ * e_book_backend_is_opening:
  * @backend: an #EBookBackend
- * @is_loaded: A flag indicating whether the backend is loaded
  *
- * Sets the flag indicating whether @backend is loaded to @is_loaded.
- * Meant to be used by backend implementations.
+ * Checks if @backend is processing its opening phase, which
+ * includes everything since the e_book_backend_open() call,
+ * through authentication, up to e_book_backend_notify_opened().
+ * This property is managed automatically and the backend deny
+ * every operation except of cancel and authenticate_user while
+ * it is being opening.
+ *
+ * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
  **/
-void
-e_book_backend_set_is_loaded (EBookBackend *backend, gboolean is_loaded)
+gboolean
+e_book_backend_is_opening (EBookBackend *backend)
 {
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	backend->priv->loaded = is_loaded;
+	return backend->priv->opening;
 }
 
 /**
@@ -808,22 +894,6 @@ e_book_backend_is_readonly (EBookBackend *backend)
 }
 
 /**
- * e_book_backend_set_is_readonly:
- * @backend: an #EBookBackend
- * @is_readonly: A flag indicating whether the backend is readonly
- *
- * Sets the flag indicating whether @backend is readonly to @is_readonly.
- * Meant to be used by backend implementations.
- **/
-void
-e_book_backend_set_is_readonly (EBookBackend *backend, gboolean is_readonly)
-{
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-
-	backend->priv->readonly = is_readonly;
-}
-
-/**
  * e_book_backend_is_removed:
  * @backend: an #EBookBackend
  *
@@ -1047,15 +1117,27 @@ e_book_backend_notify_online (EBookBackend *backend, gboolean is_online)
 /**
  * e_book_backend_notify_auth_required:
  * @backend: an #EBookBackend
+ * @is_self: Use %TRUE to indicate the authentication is required
+ *    for the @backend, otheriwse the authentication is for any
+ *    other source. Having @credentials %NULL means @is_self
+ *    automatically.
  * @credentials: an #ECredentials that contains extra information for
  *    a source for which authentication is requested.
- *    This parameter can be NULL to indicate "for this book".
+ *    This parameter can be %NULL to indicate "for this book".
  *
  * Notifies clients that @backend requires authentication in order to
- * connect. Means to be used by backend implementations.
+ * connect. This function call does not influence 'opening', but 
+ * influences 'opened' property, which is set to %FALSE when @is_self
+ * is %TRUE or @credentials is %NULL. Opening phase is finished
+ * by e_book_backend_notify_opened() if this is requested for @backend.
+ *
+ * See e_book_backend_open() for a description how the whole opening
+ * phase works.
+ *
+ * Meant to be used by backend implementations.
  **/
 void
-e_book_backend_notify_auth_required (EBookBackend *backend, const ECredentials *credentials)
+e_book_backend_notify_auth_required (EBookBackend *backend, gboolean is_self, const ECredentials *credentials)
 {
 	EBookBackendPrivate *priv;
 	GSList *clients;
@@ -1063,7 +1145,82 @@ e_book_backend_notify_auth_required (EBookBackend *backend, const ECredentials *
 	priv = backend->priv;
 	g_mutex_lock (priv->clients_mutex);
 
+	if (is_self || !credentials)
+		priv->opened = FALSE;
+
 	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
 		e_data_book_report_auth_required (E_DATA_BOOK (clients->data), credentials);
+
 	g_mutex_unlock (priv->clients_mutex);
 }
+
+/**
+ * e_book_backend_notify_opened:
+ * @backend: an #EBookBackend
+ * @error: a #GError corresponding to the error encountered during
+ *    the opening phase. Use %NULL for success. The @error is freed
+ *    automatically if not %NULL.
+ *
+ * Notifies clients that @backend finished its opening phase.
+ * See e_book_backend_open() for more information how the opening
+ * phase works. Calling this function changes 'opening' property,
+ * same as 'opened'. 'opening' is set to %FALSE and the backend
+ * is considered 'opened' only if the @error is %NULL.
+ *
+ * See also: e_book_backend_respond_opened()
+ *
+ * Note: The @error is freed automatically if not %NULL.
+ *
+ * Meant to be used by backend implementations.
+ **/
+void
+e_book_backend_notify_opened (EBookBackend *backend, GError *error)
+{
+	EBookBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+	g_mutex_lock (priv->clients_mutex);
+
+	priv->opening = FALSE;
+	priv->opened = error == NULL;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_opened (E_DATA_BOOK (clients->data), error);
+
+	g_mutex_unlock (priv->clients_mutex);
+
+	if (error)
+		g_error_free (error);
+}
+
+/**
+ * e_book_backend_respond_opened:
+ * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: an operation ID
+ * @error: result error; can be %NULL, if it isn't then it's automatically freed
+ *
+ * This is a replacement for e_data_book_respond_open() for cases where
+ * the finish of 'open' method call also finishes backend opening phase.
+ * This function covers calling of both e_data_book_respond_open() and
+ * e_book_backend_notify_opened() with the same @error.
+ *
+ * See e_book_backend_open() for more details how the opening phase works.
+ **/
+void
+e_book_backend_respond_opened (EBookBackend *backend, EDataBook *book, guint32 opid, GError *error)
+{
+	GError *copy = NULL;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (book != NULL);
+	g_return_if_fail (opid != 0);
+
+	if (error)
+		copy = g_error_copy (error);
+
+	e_data_book_respond_open (book, opid, error);
+	e_book_backend_notify_opened (backend, copy);
+}
diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h
index cd7ec1c..752b381 100644
--- a/addressbook/libedata-book/e-book-backend.h
+++ b/addressbook/libedata-book/e-book-backend.h
@@ -41,7 +41,8 @@ G_BEGIN_DECLS
 #define E_IS_BOOK_BACKEND_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND))
 #define E_BOOK_BACKEND_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), E_TYPE_BOOK_BACKEND, EBookBackendClass))
 
-#define CLIENT_BACKEND_PROPERTY_LOADED			"loaded"
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
 #define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
 #define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
 #define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
@@ -65,9 +66,9 @@ struct _EBookBackendClass {
         void	(* set_backend_property)	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
 
 	void	(* open)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
-	void	(* authenticate_user)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, ECredentials *credentials);
 	void	(* remove)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
 	void	(* set_online)			(EBookBackend *backend, gboolean is_online);
+	void	(* authenticate_user)		(EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials);
 
 	void	(* create_contact)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
 	void	(* remove_contacts)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list);
@@ -94,16 +95,17 @@ gboolean	e_book_backend_add_client	(EBookBackend *backend, EDataBook *book);
 void		e_book_backend_remove_client	(EBookBackend *backend, EDataBook *book);
 
 gboolean	e_book_backend_is_online	(EBookBackend *backend);
-gboolean	e_book_backend_is_loaded	(EBookBackend *backend);
+gboolean	e_book_backend_is_opened	(EBookBackend *backend);
+gboolean	e_book_backend_is_opening	(EBookBackend *backend);
 gboolean	e_book_backend_is_readonly	(EBookBackend *backend);
 gboolean	e_book_backend_is_removed	(EBookBackend *backend);
 void		e_book_backend_set_online	(EBookBackend *backend, gboolean is_online);
+void		e_book_backend_authenticate_user(EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials);
 
 void		e_book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name);
 void		e_book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
 
 void		e_book_backend_open		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
-void		e_book_backend_authenticate_user(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, ECredentials *credentials);
 void		e_book_backend_remove		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
 void		e_book_backend_create_contact	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
 void		e_book_backend_remove_contacts	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list);
@@ -124,15 +126,16 @@ void		e_book_backend_notify_complete	(EBookBackend *backend);
 void		e_book_backend_notify_error	(EBookBackend *backend, const gchar *message);
 void		e_book_backend_notify_readonly	(EBookBackend *backend, gboolean is_readonly);
 void		e_book_backend_notify_online	(EBookBackend *backend, gboolean is_online);
-void		e_book_backend_notify_auth_required (EBookBackend *backend, const ECredentials *credentials);
+void		e_book_backend_notify_auth_required (EBookBackend *backend, gboolean is_self, const ECredentials *credentials);
+void		e_book_backend_notify_opened	(EBookBackend *backend, GError *error);
 
 void		e_book_backend_sync		(EBookBackend *backend);
 
 /* protected functions for subclasses */
-void		e_book_backend_set_is_loaded	(EBookBackend *backend, gboolean is_loaded);
-void		e_book_backend_set_is_readonly	(EBookBackend *backend, gboolean is_readonly);
 void		e_book_backend_set_is_removed	(EBookBackend *backend, gboolean is_removed);
 
+void		e_book_backend_respond_opened	(EBookBackend *backend, EDataBook *book, guint32 opid, GError *error);
+
 G_END_DECLS
 
 #endif /* __E_BOOK_BACKEND_H__ */
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index f70a586..9fcceb6 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -313,12 +313,6 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 		return TRUE;
 	}
 
-	/* Remove a pending exit */
-	if (priv->exit_timeout) {
-		g_source_remove (priv->exit_timeout);
-		priv->exit_timeout = 0;
-	}
-
 	g_mutex_lock (priv->backends_lock);
 
 	source = e_source_new_from_standalone_xml (in_source);
@@ -382,6 +376,12 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 		return TRUE;
 	}
 
+	/* Remove a pending exit */
+	if (priv->exit_timeout) {
+		g_source_remove (priv->exit_timeout);
+		priv->exit_timeout = 0;
+	}
+
 	path = construct_book_factory_path ();
 	book = e_data_book_new (backend, source);
 	g_hash_table_insert (priv->books, g_strdup (path), book);
diff --git a/addressbook/libedata-book/e-data-book-types.h b/addressbook/libedata-book/e-data-book-types.h
index cf608dc..5434815 100644
--- a/addressbook/libedata-book/e-data-book-types.h
+++ b/addressbook/libedata-book/e-data-book-types.h
@@ -46,6 +46,7 @@ typedef struct _EDataBookClass   EDataBookClass;
 
 typedef enum {
 	E_DATA_BOOK_STATUS_SUCCESS,
+	E_DATA_BOOK_STATUS_BUSY,
 	E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,
 	E_DATA_BOOK_STATUS_PERMISSION_DENIED,
 	E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 358adaa..685d784 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -541,7 +541,7 @@ e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
 
 	g_mutex_unlock (priv->pending_mutex);
 
-	strv_error = e_gdbus_book_view_encode_error (error);
+	strv_error = e_gdbus_templates_encode_error (error);
 	e_gdbus_book_view_emit_complete (priv->gdbus_object, (const gchar * const *) strv_error);
 	g_strfreev (strv_error);
 }
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 9fd618a..29f1a5b 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -137,10 +137,6 @@ operation_thread (gpointer data, gpointer user_data)
 	case OP_OPEN:
 		e_book_backend_open (backend, op->book, op->id, op->cancellable, op->d.only_if_exists);
 		break;
-	case OP_AUTHENTICATE:
-		e_book_backend_authenticate_user (backend, op->book, op->id, op->cancellable, op->d.credentials);
-		e_credentials_free (op->d.credentials);
-		break;
 	case OP_ADD_CONTACT:
 		e_book_backend_create_contact (backend, op->book, op->id, op->cancellable, op->d.vcard);
 		g_free (op->d.vcard);
@@ -215,6 +211,10 @@ operation_thread (gpointer data, gpointer user_data)
 		}
 		g_free (op->d.query);
 		break;
+	case OP_AUTHENTICATE:
+		e_book_backend_authenticate_user (backend, op->cancellable, op->d.credentials);
+		e_credentials_free (op->d.credentials);
+		break;
 	case OP_CANCEL_OPERATION:
 		g_static_rec_mutex_lock (&op->book->priv->pending_ops_lock);
 
@@ -285,6 +285,7 @@ e_data_book_status_to_string (EDataBookStatus status)
 		const gchar *msg;
 	} statuses[] = {
 		{ E_DATA_BOOK_STATUS_SUCCESS,				N_("Success") },
+		{ E_DATA_BOOK_STATUS_BUSY,				N_("Backend is busy") },
 		{ E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,		N_("Repository offline") },
 		{ E_DATA_BOOK_STATUS_PERMISSION_DENIED,			N_("Permission denied") },
 		{ E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,			N_("Contact not found") },
@@ -326,6 +327,7 @@ e_data_book_error_quark (void)
 
 	static const GDBusErrorEntry entries[] = {
 		{ E_DATA_BOOK_STATUS_SUCCESS,				ERR_PREFIX "Success" },
+		{ E_DATA_BOOK_STATUS_BUSY,				ERR_PREFIX "Busy" },
 		{ E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,		ERR_PREFIX "RepositoryOffline" },
 		{ E_DATA_BOOK_STATUS_PERMISSION_DENIED,			ERR_PREFIX "PermissionDenied" },
 		{ E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,			ERR_PREFIX "ContactNotFound" },
@@ -541,28 +543,6 @@ impl_Book_getContactList (EGdbusBook *object, GDBusMethodInvocation *invocation,
 }
 
 static gboolean
-impl_Book_authenticateUser (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataBook *book)
-{
-	OperationData *op;
-
-	if (in_credentials == NULL) {
-		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_ARG, NULL);
-		/* Translators: This is prefix to a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot authenticate user: "));
-		g_error_free (error);
-		return TRUE;
-	}
-
-	op = op_new (OP_AUTHENTICATE, book);
-	op->d.credentials = e_credentials_new_strv (in_credentials);
-
-	e_gdbus_book_complete_authenticate_user (book->priv->gdbus_object, invocation, op->id);
-	e_operation_pool_push (ops_pool, op);
-
-	return TRUE;
-}
-
-static gboolean
 impl_Book_addContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_vcard, EDataBook *book)
 {
 	OperationData *op;
@@ -678,6 +658,28 @@ impl_Book_getBookView (EGdbusBook *object, GDBusMethodInvocation *invocation, co
 }
 
 static gboolean
+impl_Book_authenticateUser (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataBook *book)
+{
+	OperationData *op;
+
+	if (in_credentials == NULL) {
+		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_ARG, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Cannot authenticate user: "));
+		g_error_free (error);
+		return TRUE;
+	}
+
+	op = op_new (OP_AUTHENTICATE, book);
+	op->d.credentials = e_credentials_new_strv (in_credentials);
+
+	e_gdbus_book_complete_authenticate_user (book->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
+}
+
+static gboolean
 impl_Book_cancelOperation (EGdbusBook *object, GDBusMethodInvocation *invocation, guint in_opid, EDataBook *book)
 {
 	OperationData *op;
@@ -824,20 +826,6 @@ e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, GError *err
 }
 
 void
-e_data_book_respond_authenticate_user (EDataBook *book, guint32 opid, GError *error)
-{
-	op_complete (book, opid);
-
-	/* Translators: This is prefix to a detailed error message */
-	g_prefix_error (&error, "%s", _("Cannot authenticate user: "));
-
-	e_gdbus_book_emit_authenticate_user_done (book->priv->gdbus_object, opid, error);
-
-	if (error)
-		g_error_free (error);
-}
-
-void
 e_data_book_respond_create (EDataBook *book, guint32 opid, GError *error, const EContact *contact)
 {
 	gchar *gdbus_uid = NULL;
@@ -946,6 +934,23 @@ e_data_book_report_auth_required (EDataBook *book, const ECredentials *credentia
 	g_strfreev (strv);
 }
 
+/* Reports to associated client that opening phase of the book is finished.
+   error being NULL means successfully, otherwise reports an error which happened
+   during opening phase. By opening phase is meant a process including successfull
+   authentication to the server/storage.
+*/
+void
+e_data_book_report_opened (EDataBook *book, const GError *error)
+{
+	gchar **strv_error;
+
+	strv_error = e_gdbus_templates_encode_error (error);
+
+	e_gdbus_book_emit_opened (book->priv->gdbus_object, (const gchar * const *) strv_error);
+
+	g_strfreev (strv_error);
+}
+
 /**
  * e_data_book_register_gdbus_object:
  *
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index 1c7ea9c..465a2ba 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -20,8 +20,8 @@
  * Author: Ross Burton <ross linux intel com>
  */
 
-#ifndef __E_DATA_BOOK_H__
-#define __E_DATA_BOOK_H__
+#ifndef E_DATA_BOOK_H
+#define E_DATA_BOOK_H
 
 #include <glib-object.h>
 #include <gio/gio.h>
@@ -140,7 +140,6 @@ void		e_data_book_respond_set_backend_property	(EDataBook *book, guint32 opid, G
 void		e_data_book_respond_create			(EDataBook *book, guint32 opid, GError *error, const EContact *contact);
 void		e_data_book_respond_remove_contacts		(EDataBook *book, guint32 opid, GError *error, const GSList *ids);
 void		e_data_book_respond_modify			(EDataBook *book, guint32 opid, GError *error, const EContact *contact);
-void		e_data_book_respond_authenticate_user		(EDataBook *book, guint32 opid, GError *error);
 void		e_data_book_respond_get_contact			(EDataBook *book, guint32 opid, GError *error, const gchar *vcard);
 void		e_data_book_respond_get_contact_list		(EDataBook *book, guint32 opid, GError *error, const GSList *cards);
 
@@ -148,9 +147,10 @@ void		e_data_book_report_error			(EDataBook *book, const gchar *message);
 void		e_data_book_report_readonly			(EDataBook *book, gboolean readonly);
 void		e_data_book_report_online			(EDataBook *book, gboolean is_online);
 void		e_data_book_report_auth_required		(EDataBook *book, const ECredentials *credentials);
+void		e_data_book_report_opened			(EDataBook *book, const GError *error);
 
 gchar *		e_data_book_string_slist_to_comma_string	(const GSList *strings);
 
 G_END_DECLS
 
-#endif /* __E_DATA_BOOK_H__ */
+#endif /* E_DATA_BOOK_H */
diff --git a/addressbook/libegdbus/e-gdbus-book-view.c b/addressbook/libegdbus/e-gdbus-book-view.c
index f8ff514..dfa40a5 100644
--- a/addressbook/libegdbus/e-gdbus-book-view.c
+++ b/addressbook/libegdbus/e-gdbus-book-view.c
@@ -210,50 +210,6 @@ e_gdbus_book_view_emit_progress (EGdbusBookView *object, guint arg_percent, cons
 	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
 }
 
-/* free returned pointer with g_strfreev() */
-gchar **
-e_gdbus_book_view_encode_error (const GError *in_error)
-{
-	gchar **strv;
-
-	strv = g_new0 (gchar *, 3);
-
-	if (!in_error) {
-		strv[0] = g_strdup ("");
-		strv[1] = g_strdup ("");
-	} else {
-		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
-
-		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
-		strv[1] = e_util_utf8_make_valid (in_error->message);
-
-		g_free (dbus_error_name);
-	}
-
-	return strv;
-}
-
-/* free returned pointer with g_error_free(), of not NULL */
-GError *
-e_gdbus_book_view_decode_error (const gchar * const *in_strv)
-{
-	GError *error = NULL;
-	const gchar *error_name, *error_message;
-
-	g_return_val_if_fail (in_strv != NULL, NULL);
-	g_return_val_if_fail (in_strv[0] != NULL, NULL);
-	g_return_val_if_fail (in_strv[1] != NULL, NULL);
-	g_return_val_if_fail (in_strv[2] == NULL, NULL);
-
-	error_name = in_strv[0];
-	error_message = in_strv[1];
-
-	if (error_name && *error_name && error_message)
-		error = g_dbus_error_new_for_dbus_error (error_name, error_message);
-
-	return error;
-}
-
 void
 e_gdbus_book_view_emit_complete (EGdbusBookView *object, const gchar * const *arg_error)
 {
diff --git a/addressbook/libegdbus/e-gdbus-book-view.h b/addressbook/libegdbus/e-gdbus-book-view.h
index 719bcbd..e959afd 100644
--- a/addressbook/libegdbus/e-gdbus-book-view.h
+++ b/addressbook/libegdbus/e-gdbus-book-view.h
@@ -148,9 +148,6 @@ void	e_gdbus_book_view_emit_objects_modified	(EGdbusBookView *object, const gcha
 void	e_gdbus_book_view_emit_objects_removed	(EGdbusBookView *object, const gchar * const *arg_uids);
 
 void	e_gdbus_book_view_emit_progress		(EGdbusBookView *object, guint arg_percent, const gchar *arg_message);
-
-gchar **e_gdbus_book_view_encode_error		(const GError *in_error);
-GError *e_gdbus_book_view_decode_error		(const gchar * const *in_strv);
 void	e_gdbus_book_view_emit_complete		(EGdbusBookView *object, const gchar * const *arg_error);
 
 G_END_DECLS
diff --git a/addressbook/libegdbus/e-gdbus-book.c b/addressbook/libegdbus/e-gdbus-book.c
index 97b39c9..a3dbcd1 100644
--- a/addressbook/libegdbus/e-gdbus-book.c
+++ b/addressbook/libegdbus/e-gdbus-book.c
@@ -39,10 +39,9 @@ enum
 	__READONLY_SIGNAL,
 	__ONLINE_SIGNAL,
 	__AUTH_REQUIRED_SIGNAL,
+	__OPENED_SIGNAL,
 	__OPEN_METHOD,
 	__OPEN_DONE_SIGNAL,
-	__AUTHENTICATE_USER_METHOD,
-	__AUTHENTICATE_USER_DONE_SIGNAL,
 	__REMOVE_METHOD,
 	__REMOVE_DONE_SIGNAL,
 	__GET_CONTACT_METHOD,
@@ -61,6 +60,7 @@ enum
 	__SET_BACKEND_PROPERTY_DONE_SIGNAL,
 	__GET_VIEW_METHOD,
 	__GET_VIEW_DONE_SIGNAL,
+	__AUTHENTICATE_USER_METHOD,
 	__CANCEL_OPERATION_METHOD,
 	__CANCEL_ALL_METHOD,
 	__CLOSE_METHOD,
@@ -113,9 +113,9 @@ E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRING  (GDBUS_BOOK_INTERFACE_NAME, backend
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_BOOK_INTERFACE_NAME, readonly)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_BOOK_INTERFACE_NAME, online)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_BOOK_INTERFACE_NAME, auth_required)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_BOOK_INTERFACE_NAME, opened)
 
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, open)
-E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, authenticate_user)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, remove)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_BOOK_INTERFACE_NAME, get_contact)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV	(GDBUS_BOOK_INTERFACE_NAME, get_contact_list)
@@ -140,10 +140,10 @@ e_gdbus_book_default_init (EGdbusBookIface *iface)
 	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusBookIface, "readonly",		readonly,	__READONLY_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusBookIface, "online",		online,		__ONLINE_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusBookIface, "auth_required", 	auth_required,	__AUTH_REQUIRED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusBookIface, "opened", 		opened,		__OPENED_SIGNAL)
 
 	/* GObject signals definitions for D-Bus methods: */
 	E_INIT_GDBUS_METHOD_ASYNC_BOOLEAN__VOID	(EGdbusBookIface, "open",			open, __OPEN_METHOD, __OPEN_DONE_SIGNAL)
-	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusBookIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD, __AUTHENTICATE_USER_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusBookIface, "remove",			remove, __REMOVE_METHOD, __REMOVE_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getContact",			get_contact, __GET_CONTACT_METHOD, __GET_CONTACT_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV	(EGdbusBookIface, "getContactList",		get_contact_list, __GET_CONTACT_LIST_METHOD, __GET_CONTACT_LIST_DONE_SIGNAL)
@@ -153,6 +153,7 @@ e_gdbus_book_default_init (EGdbusBookIface *iface)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getBackendProperty",		get_backend_property, __GET_BACKEND_PROPERTY_METHOD, __GET_BACKEND_PROPERTY_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusBookIface, "setBackendProperty",		set_backend_property, __SET_BACKEND_PROPERTY_METHOD, __SET_BACKEND_PROPERTY_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getView",			get_view, __GET_VIEW_METHOD, __GET_VIEW_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_STRV		(EGdbusBookIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD)
 	E_INIT_GDBUS_METHOD_UINT		(EGdbusBookIface, "cancelOperation",		cancel_operation, __CANCEL_OPERATION_METHOD)
 	E_INIT_GDBUS_METHOD_VOID		(EGdbusBookIface, "cancelAll",			cancel_all, __CANCEL_ALL_METHOD)
 	E_INIT_GDBUS_METHOD_VOID		(EGdbusBookIface, "close",			close, __CLOSE_METHOD)
@@ -179,26 +180,6 @@ e_gdbus_book_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCan
 }
 
 void
-e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
-{
-	e_gdbus_proxy_call_strv ("authenticateUser", e_gdbus_book_call_authenticate_user, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_credentials, cancellable, callback, user_data);
-}
-
-gboolean
-e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
-{
-	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_authenticate_user);
-}
-
-gboolean
-e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
-{
-	return e_gdbus_proxy_call_sync_strv__void (proxy, in_credentials, cancellable, error,
-		e_gdbus_book_call_authenticate_user,
-		e_gdbus_book_call_authenticate_user_finish);
-}
-
-void
 e_gdbus_book_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
 	e_gdbus_proxy_call_void ("remove", e_gdbus_book_call_remove, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
@@ -410,6 +391,24 @@ e_gdbus_book_call_get_view_sync (GDBusProxy *proxy, const gchar *in_query, gchar
 }
 
 void
+e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("authenticateUser", proxy, in_credentials, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("authenticateUser", proxy, in_credentials, cancellable, error);
+}
+
+void
 e_gdbus_book_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
 	e_gdbus_proxy_method_call_uint ("cancelOperation", proxy, in_opid, cancellable, callback, user_data);
@@ -478,7 +477,6 @@ e_gdbus_book_emit_ ## _mname ## _done (EGdbusBook *object, guint arg_opid, const
 }
 
 DECLARE_EMIT_DONE_SIGNAL_0 (open,			__OPEN_DONE_SIGNAL)
-DECLARE_EMIT_DONE_SIGNAL_0 (authenticate_user,		__AUTHENTICATE_USER_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_0 (remove,			__REMOVE_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_1 (get_contact,		__GET_CONTACT_DONE_SIGNAL, const gchar *)
 DECLARE_EMIT_DONE_SIGNAL_1 (get_contact_list,		__GET_CONTACT_LIST_DONE_SIGNAL, const gchar * const *)
@@ -516,13 +514,19 @@ e_gdbus_book_emit_auth_required (EGdbusBook *object, const gchar * const *arg_cr
 	g_signal_emit (object, signals[__AUTH_REQUIRED_SIGNAL], 0, arg_credentials);
 }
 
+void
+e_gdbus_book_emit_opened (EGdbusBook *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__OPENED_SIGNAL], 0, arg_error);
+}
+
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, backend_error, message, "s")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, readonly, is_readonly, "b")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, online, is_online, "b")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, auth_required, credentials, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, opened, error, "as")
 
 E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, open, only_if_exists, "b")
-E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, authenticateUser, credentials, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_0			(book, remove)
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getContact, uid, "s", vcard, "s")
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getContactList, query, "s", vcards, "as")
@@ -533,6 +537,7 @@ E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getBackendProperty, prop_name,
 E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, setBackendProperty, prop_name_value, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getView, query, "s", view, "s")
 
+E_DECLARE_GDBUS_SYNC_METHOD_1			(book, authenticateUser, credentials, "as")
 E_DECLARE_GDBUS_SYNC_METHOD_1			(book, cancelOperation, opid, "u")
 E_DECLARE_GDBUS_SYNC_METHOD_0			(book, cancelAll)
 E_DECLARE_GDBUS_SYNC_METHOD_0			(book, close)
@@ -540,7 +545,6 @@ E_DECLARE_GDBUS_SYNC_METHOD_0			(book, close)
 static const GDBusMethodInfo * const e_gdbus_book_method_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, open),
-	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, authenticateUser),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, remove),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getContact),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getContactList),
@@ -550,6 +554,7 @@ static const GDBusMethodInfo * const e_gdbus_book_method_info_pointers[] =
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getBackendProperty),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, setBackendProperty),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getView),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, authenticateUser),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, cancelOperation),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, cancelAll),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, close),
@@ -562,9 +567,9 @@ static const GDBusSignalInfo * const e_gdbus_book_signal_info_pointers[] =
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, readonly),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, online),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, auth_required),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, opened),
 
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, open_done),
-	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, authenticateUser_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, remove_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getContact_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getContactList_done),
@@ -769,7 +774,6 @@ e_gdbus_book_proxy_init (EGdbusBookProxy *proxy)
 	proxy->priv->pending_ops = e_gdbus_async_op_keeper_create_pending_ops (E_GDBUS_ASYNC_OP_KEEPER (proxy));
 
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (open);
-	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (authenticate_user);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_contact);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_contact_list);
diff --git a/addressbook/libegdbus/e-gdbus-book.h b/addressbook/libegdbus/e-gdbus-book.h
index 6223cce..0249539 100644
--- a/addressbook/libegdbus/e-gdbus-book.h
+++ b/addressbook/libegdbus/e-gdbus-book.h
@@ -116,14 +116,12 @@ struct _EGdbusBookIface
 	void	(*readonly)			(EGdbusBook *object, gboolean arg_is_readonly);
 	void	(*online)			(EGdbusBook *object, gboolean arg_is_online);
 	void	(*auth_required)		(EGdbusBook *object, const gchar * const *arg_credentials);
+	void	(*opened)			(EGdbusBook *object, const gchar * const *arg_error);
 
 	/* Signal handlers for handling D-Bus method calls: */
 	gboolean (*handle_open)			(EGdbusBook *object, GDBusMethodInvocation *invocation, gboolean in_only_if_exists);
 	void	 (*open_done)			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
 
-	gboolean (*handle_authenticate_user)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
-	void	 (*authenticate_user_done)	(EGdbusBook *object, guint arg_opid, const GError *arg_error);
-
 	gboolean (*handle_remove)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
 	void	 (*remove_done)			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
 
@@ -151,6 +149,7 @@ struct _EGdbusBookIface
 	gboolean (*handle_get_view)		(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_query);
 	void	 (*get_view_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar **out_view);
 
+	gboolean (*handle_authenticate_user)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
 	gboolean (*handle_cancel_operation)	(EGdbusBook *object, GDBusMethodInvocation *invocation, guint in_opid);
 	gboolean (*handle_cancel_all)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
 	gboolean (*handle_close)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
@@ -164,10 +163,6 @@ void		e_gdbus_book_call_open (GDBusProxy *proxy, gboolean in_only_if_exists, GCa
 gboolean	e_gdbus_book_call_open_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_book_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error);
 
-void		e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean	e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
-gboolean	e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
-
 void		e_gdbus_book_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean	e_gdbus_book_call_remove_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_book_call_remove_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error);
@@ -206,6 +201,10 @@ void		e_gdbus_book_call_get_view (GDBusProxy *proxy, const gchar *in_query, GCan
 gboolean	e_gdbus_book_call_get_view_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_view_path, GError **error);
 gboolean	e_gdbus_book_call_get_view_sync (GDBusProxy *proxy, const gchar *in_query, gchar **out_view_path, GCancellable *cancellable, GError **error);
 
+void		e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
+
 void		e_gdbus_book_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean	e_gdbus_book_call_cancel_operation_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_book_call_cancel_operation_sync (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error);
@@ -220,7 +219,6 @@ gboolean	e_gdbus_book_call_close_sync (GDBusProxy *proxy, GCancellable *cancella
 
 /* D-Bus Methods Completion Helpers */
 #define e_gdbus_book_complete_open				e_gdbus_complete_async_method
-#define e_gdbus_book_complete_authenticate_user			e_gdbus_complete_async_method
 #define e_gdbus_book_complete_remove				e_gdbus_complete_async_method
 #define e_gdbus_book_complete_get_contact			e_gdbus_complete_async_method
 #define e_gdbus_book_complete_get_contact_list			e_gdbus_complete_async_method
@@ -230,12 +228,12 @@ gboolean	e_gdbus_book_call_close_sync (GDBusProxy *proxy, GCancellable *cancella
 #define e_gdbus_book_complete_get_backend_property		e_gdbus_complete_async_method
 #define e_gdbus_book_complete_set_backend_property		e_gdbus_complete_async_method
 #define e_gdbus_book_complete_get_view				e_gdbus_complete_async_method
+#define e_gdbus_book_complete_authenticate_user			e_gdbus_complete_sync_method_void
 #define e_gdbus_book_complete_cancel_operation			e_gdbus_complete_sync_method_void
 #define e_gdbus_book_complete_cancel_all			e_gdbus_complete_sync_method_void
 #define e_gdbus_book_complete_close				e_gdbus_complete_sync_method_void
 
 void e_gdbus_book_emit_open_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
-void e_gdbus_book_emit_authenticate_user_done		(EGdbusBook *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_book_emit_remove_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_book_emit_get_contact_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar *out_vcard);
 void e_gdbus_book_emit_get_contact_list_done		(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar * const *out_vcards);
@@ -251,6 +249,7 @@ void e_gdbus_book_emit_backend_error	(EGdbusBook *object, const gchar *arg_messa
 void e_gdbus_book_emit_readonly		(EGdbusBook *object, gboolean arg_is_readonly);
 void e_gdbus_book_emit_online		(EGdbusBook *object, gboolean arg_is_online);
 void e_gdbus_book_emit_auth_required	(EGdbusBook *object, const gchar * const *arg_credentials);
+void e_gdbus_book_emit_opened		(EGdbusBook *object, const gchar * const *arg_error);
 
 G_END_DECLS
 
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 20020a7..0eca575 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -2485,16 +2485,18 @@ caldav_do_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellab
 
 		if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired) || g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
 			g_clear_error (&local_error);
-			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbdav), priv->credentials);
+			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbdav), TRUE, priv->credentials);
+		} else {
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 		}
 
 		if (local_error)
 			g_propagate_error (perror, local_error);
 	} else {
 		priv->read_only = TRUE;
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 	}
 
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), priv->loaded);
 	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), priv->read_only);
 	e_cal_backend_notify_online (E_CAL_BACKEND (backend), priv->is_online);
 
@@ -2502,7 +2504,7 @@ caldav_do_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellab
 }
 
 static void
-caldav_authenticate_user (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error)
+caldav_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -2517,7 +2519,7 @@ caldav_authenticate_user (ECalBackendSync *backend, EDataCal *cal, GCancellable
 
 	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
 		g_mutex_unlock (priv->busy_lock);
-		g_propagate_error (error, EDC_ERROR (AuthenticationFailed));
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
 		return;
 	}
 
@@ -2592,8 +2594,6 @@ caldav_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellabl
 		g_cond_wait (priv->slave_gone_cond, priv->busy_lock);
 	}
 
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), priv->loaded);
-
 	g_mutex_unlock (priv->busy_lock);
 }
 
diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c b/calendar/backends/contacts/e-cal-backend-contacts.c
index 42052e3..366a229 100644
--- a/calendar/backends/contacts/e-cal-backend-contacts.c
+++ b/calendar/backends/contacts/e-cal-backend-contacts.c
@@ -978,13 +978,14 @@ e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal, GCancellab
 			g_error_free (error);
 
 		g_propagate_error (perror, EDC_ERROR (OtherError));
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (OtherError));
 		return;
 	}
 
 	priv->addressbook_loaded = TRUE;
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
 	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
 	e_cal_backend_notify_online (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 }
 
 /* Add_timezone handler for the file backend */
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index b1189ee..956862a 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -983,8 +983,6 @@ open_cal (ECalBackendFile *cbfile, const gchar *uristr, GError **perror)
 	scan_vcalendar (cbfile);
 
 	prepare_refresh_data (cbfile);
-
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (cbfile), TRUE);
 }
 
 typedef struct
@@ -1141,8 +1139,6 @@ reload_cal (ECalBackendFile *cbfile, const gchar *uristr, GError **perror)
 	/* Free old data */
 
 	free_calendar_components (comp_uid_hash_old, icalcomp_old);
-
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (cbfile), TRUE);
 }
 
 static void
@@ -1179,8 +1175,6 @@ create_cal (ECalBackendFile *cbfile, const gchar *uristr, GError **perror)
 	g_free (priv->custom_file);
 	priv->custom_file = g_strdup (uristr);
 	prepare_refresh_data (cbfile);
-
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (cbfile), TRUE);
 }
 
 static gchar *
@@ -1290,7 +1284,9 @@ e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *
 	e_cal_backend_notify_online (E_CAL_BACKEND (backend), TRUE);
 
 	if (err)
-		g_propagate_error (perror, err);
+		g_propagate_error (perror, g_error_copy (err));
+
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), err);
 }
 
 static void
diff --git a/calendar/backends/groupwise/e-cal-backend-groupwise.c b/calendar/backends/groupwise/e-cal-backend-groupwise.c
index 413ffe0..3f54c05 100644
--- a/calendar/backends/groupwise/e-cal-backend-groupwise.c
+++ b/calendar/backends/groupwise/e-cal-backend-groupwise.c
@@ -1150,7 +1150,6 @@ connect_to_server (ECalBackendGroupwise *cbgw, GError **perror)
 		}
 
 		e_cal_backend_store_load (priv->store);
-		e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
 
 		/* spawn a new thread for opening the calendar */
 		thread = g_thread_create ((GThreadFunc) cache_init, cbgw, FALSE, &error);
@@ -1378,6 +1377,7 @@ e_cal_backend_groupwise_open (ECalBackendSync *backend, EDataCal *cal, GCancella
 		if (!display_contents || !g_str_equal (display_contents, "1")) {
 			PRIV_UNLOCK (priv);
 			g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (RepositoryOffline));
 			return;
 		}
 
@@ -1388,26 +1388,35 @@ e_cal_backend_groupwise_open (ECalBackendSync *backend, EDataCal *cal, GCancella
 			if (!priv->store) {
 				PRIV_UNLOCK (priv);
 				g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
+				e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR_EX (OtherError, _("Could not create cache file")));
 				return;
 			}
 		}
 
 		e_cal_backend_store_load (priv->store);
-		e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 		PRIV_UNLOCK (priv);
 		return;
 	}
 
-	if (priv->credentials)
-		connect_to_server (cbgw, perror);
-	else
-		e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbgw), priv->credentials);
+	if (priv->credentials) {
+		GError *local_error = NULL;
+
+		connect_to_server (cbgw, &local_error);
+
+		if (!local_error)
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
+		else
+			g_propagate_error (perror, local_error);
+	} else {
+		e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbgw), TRUE, priv->credentials);
+	}
 
 	PRIV_UNLOCK (priv);
 }
 
 static void
-e_cal_backend_groupwise_authenticate_user (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error)
+e_cal_backend_groupwise_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
 {
 	ECalBackendGroupwise        *cbgw;
 	ECalBackendGroupwisePrivate *priv;
@@ -1474,8 +1483,8 @@ e_cal_backend_groupwise_set_online (ECalBackend *backend, gboolean is_online)
 		priv->read_only = FALSE;
 		e_cal_backend_notify_online (backend, priv->is_online);
 		e_cal_backend_notify_readonly (backend, priv->read_only);
-		if (e_cal_backend_is_loaded (backend))
-			e_cal_backend_notify_auth_required (backend, priv->credentials);
+		if (e_cal_backend_is_opened (backend))
+			e_cal_backend_notify_auth_required (backend, TRUE, priv->credentials);
 	} else {
 		/* FIXME: make sure we update the cache before closing the connection */
 		in_offline (cbgw);
diff --git a/calendar/backends/http/e-cal-backend-http.c b/calendar/backends/http/e-cal-backend-http.c
index 41becd9..b187587 100644
--- a/calendar/backends/http/e-cal-backend-http.c
+++ b/calendar/backends/http/e-cal-backend-http.c
@@ -414,7 +414,7 @@ retrieval_done (SoupSession *session, SoupMessage *msg, ECalBackendHttp *cbhttp)
 		if (!priv->opened) {
 			if (msg->status_code == 401 || msg->status_code == 403) {
 				priv->requires_auth = TRUE;
-				e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), priv->credentials);
+				e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
 				return;
 			} else
 				e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
@@ -730,8 +730,10 @@ e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *
 	priv = cbhttp->priv;
 
 	/* already opened, thus can skip all this initialization */
-	if (priv->opened)
+	if (priv->opened) {
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 		return;
+	}
 
 	source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
 
@@ -756,26 +758,31 @@ e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *
 
 		if (!priv->store) {
 			g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR_EX (OtherError, _("Could not create cache file")));
 			return;
 		}
 	}
 
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
 	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
 	e_cal_backend_notify_online (E_CAL_BACKEND (backend), priv->is_online);
 
 	if (priv->is_online) {
-		if (e_source_get_property (source, "auth"))
-			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), priv->credentials);
-		else if (priv->requires_auth && perror && !*perror)
+		if (e_source_get_property (source, "auth")) {
+			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
+		} else if (priv->requires_auth && perror && !*perror) {
 			g_propagate_error (perror, EDC_ERROR (AuthenticationRequired));
-		else
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (AuthenticationRequired));
+		} else {
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 			g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
+		}
+	} else {
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 	}
 }
 
 static void
-e_cal_backend_http_authenticate_user (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error)
+e_cal_backend_http_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
 {
 	ECalBackendHttp        *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -784,7 +791,7 @@ e_cal_backend_http_authenticate_user (ECalBackendSync *backend, EDataCal *cal, G
 	priv  = cbhttp->priv;
 
 	if (priv->credentials && credentials && e_credentials_equal_keys (priv->credentials, credentials, E_CREDENTIALS_KEY_USERNAME, E_CREDENTIALS_KEY_PASSWORD, NULL)) {
-		g_propagate_error (error, EDC_ERROR (AuthenticationFailed));
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
 		return;
 	}
 
@@ -792,7 +799,7 @@ e_cal_backend_http_authenticate_user (ECalBackendSync *backend, EDataCal *cal, G
 	priv->credentials = NULL;
 
 	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
-		g_propagate_error (error, EDC_ERROR (AuthenticationFailed));
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
 		return;
 	}
 
@@ -848,7 +855,7 @@ e_cal_backend_http_set_online (ECalBackend *backend, gboolean is_online)
 	cbhttp = E_CAL_BACKEND_HTTP (backend);
 	priv = cbhttp->priv;
 
-	loaded = e_cal_backend_is_loaded (backend);
+	loaded = e_cal_backend_is_opened (backend);
 
 	if ((priv->is_online ? 1 : 0) != (is_online ? 1 : 0)) {
 		priv->is_online = is_online;
diff --git a/calendar/backends/weather/e-cal-backend-weather.c b/calendar/backends/weather/e-cal-backend-weather.c
index 98657ef..a17cb94 100644
--- a/calendar/backends/weather/e-cal-backend-weather.c
+++ b/calendar/backends/weather/e-cal-backend-weather.c
@@ -514,7 +514,7 @@ e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, GCancellabl
 
 		/* do we require to load this new store */
 		e_cal_backend_store_load (priv->store);
-		e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 
 		if (!priv->is_online)
 			return;
@@ -523,7 +523,7 @@ e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, GCancellabl
 			priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, cbw);
 	}
 
-	e_cal_backend_set_is_loaded (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 }
 
 static void
@@ -740,7 +740,7 @@ e_cal_backend_weather_set_online (ECalBackend *backend, gboolean is_online)
 	cbw = E_CAL_BACKEND_WEATHER (backend);
 	priv = cbw->priv;
 
-	loaded = e_cal_backend_is_loaded (backend);
+	loaded = e_cal_backend_is_opened (backend);
 
 	if ((priv->is_online ? 1: 0) != (is_online ? 1 : 0)) {
 		priv->is_online = is_online;
diff --git a/calendar/libecal/e-cal-client-view.c b/calendar/libecal/e-cal-client-view.c
index 1ffb0ff..8a56e76 100644
--- a/calendar/libecal/e-cal-client-view.c
+++ b/calendar/libecal/e-cal-client-view.c
@@ -182,14 +182,14 @@ progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message,
 static void
 complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalClientView *view)
 {
-	GError *error;
+	GError *error = NULL;
 
 	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
 
 	if (!view->priv->running)
 		return;
 
-	error = e_gdbus_cal_view_decode_error (arg_error);
+	g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
 
 	g_signal_emit (G_OBJECT (view), signals[COMPLETE], 0, error);
 
@@ -493,7 +493,7 @@ e_cal_client_view_stop (ECalClientView *view, GError **error)
  *
  * Client can instruct server to which fields it is interested in only, thus
  * the server can return less data over the wire. The server can still return
- * complete objects, this is just a hint to it that the listef fields will
+ * complete objects, this is just a hint to it that the listed fields will
  * be used only. The UID/RID fields are returned always. Initial views has
  * no restriction, and using %NULL for @only_fields will unset any previous
  * changes.
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 3cb33f1..9b5c47a 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -76,7 +76,7 @@ G_DEFINE_TYPE (ECalClient, e_cal_client, E_TYPE_CLIENT)
  *   Preferred way of retrieving this property is by
  *   calling e_cal_client_get_default_object().
  *
- * See also: @CLIENT_BACKEND_PROPERTY_LOADED,
+ * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
  *   @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
  *   @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
  **/
@@ -157,6 +157,7 @@ unwrap_dbus_error (GError *error, GError **client_error)
 		{ err ("NoSuchCal",				E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR) },
 		{ err ("UnknownUser",				E_CAL_CLIENT_ERROR_UNKNOWN_USER) },
 	}, cl_errors[] = {
+		{ err ("Busy",					E_CLIENT_ERROR_BUSY) },
 		{ err ("InvalidArg",				E_CLIENT_ERROR_INVALID_ARG) },
 		{ err ("RepositoryOffline",			E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_CLIENT_ERROR_PERMISSION_DENIED) },
@@ -403,6 +404,22 @@ auth_required_cb (EGdbusCal *object, const gchar * const *credentials_strv, ECal
 }
 
 static void
+opened_cb (EGdbusCal *object, const gchar * const *error_strv, ECalClient *client)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (error_strv != NULL);
+	g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
+
+	e_client_emit_opened (E_CLIENT (client), error);
+
+	if (error)
+		g_error_free (error);
+}
+
+static void
 free_busy_data_cb (EGdbusCal *object, const gchar * const *free_busy_strv, ECalClient *client)
 {
 	GSList *ecalcomps = NULL;
@@ -570,6 +587,7 @@ e_cal_client_new (ESource *source, ECalClientSourceType source_type, GError **er
 	g_signal_connect (client->priv->gdbus_cal, "readonly", G_CALLBACK (readonly_cb), client);
 	g_signal_connect (client->priv->gdbus_cal, "online", G_CALLBACK (online_cb), client);
 	g_signal_connect (client->priv->gdbus_cal, "auth-required", G_CALLBACK (auth_required_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "opened", G_CALLBACK (opened_cb), client);
 	g_signal_connect (client->priv->gdbus_cal, "free-busy-data", G_CALLBACK (free_busy_data_cb), client);
 
 	return client;
diff --git a/calendar/libecal/e-cal-view.c b/calendar/libecal/e-cal-view.c
index 3302198..a7dcd22 100644
--- a/calendar/libecal/e-cal-view.c
+++ b/calendar/libecal/e-cal-view.c
@@ -165,11 +165,11 @@ progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message,
 static void
 complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalView *view)
 {
-	GError *error;
+	GError *error = NULL;
 
 	g_return_if_fail (E_IS_CAL_VIEW (view));
 
-	error = e_gdbus_cal_view_decode_error (arg_error);
+	g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
 
 	#ifndef E_CAL_DISABLE_DEPRECATED
 	g_signal_emit (G_OBJECT (view), signals[VIEW_DONE], 0, error ? error->code : 0);
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index 9a2d37c..7d70e98 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -230,6 +230,7 @@ get_status_from_error (const GError *error)
 		ECalendarStatus err_code;
 	} errors[] = {
 		{ err ("Success",				E_CALENDAR_STATUS_OK) },
+		{ err ("Busy",					E_CALENDAR_STATUS_BUSY) },
 		{ err ("RepositoryOffline",			E_CALENDAR_STATUS_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_CALENDAR_STATUS_PERMISSION_DENIED) },
 		{ err ("InvalidRange",				E_CALENDAR_STATUS_OTHER_ERROR) },
diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c
index b214c4a..5c06864 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.c
+++ b/calendar/libedata-cal/e-cal-backend-sync.c
@@ -81,7 +81,6 @@ e_cal_backend_sync_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *
 /**
  * e_cal_backend_sync_authenticate_user:
  * @backend: an #ECalBackendSync
- * @cal: an #EDataCal
  * @cancellable: a #GCancellable for the operation
  * @credentials: an #ECredentials to authenticate with
  * @error: #GError to set, when something fails
@@ -89,13 +88,12 @@ e_cal_backend_sync_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *
  * Authenticates @backend with given @credentials.
  **/
 void
-e_cal_backend_sync_authenticate_user (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error)
+e_cal_backend_sync_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
 {
 	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (E_IS_DATA_CAL (cal), InvalidArg);
 	e_return_data_cal_error_if_fail (credentials, InvalidArg);
 
-	LOCK_WRAPPER (authenticate_user_sync, (backend, cal, cancellable, credentials, error));
+	LOCK_WRAPPER (authenticate_user_sync, (backend, cancellable, credentials, error));
 }
 
 /**
@@ -498,13 +496,13 @@ cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellabl
 }
 
 static void
-cal_backend_authenticate_user (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, ECredentials *credentials)
+cal_backend_authenticate_user (ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	GError *error = NULL;
 
-	e_cal_backend_sync_authenticate_user (E_CAL_BACKEND_SYNC (backend), cal, cancellable, credentials, &error);
+	e_cal_backend_sync_authenticate_user (E_CAL_BACKEND_SYNC (backend), cancellable, credentials, &error);
 
-	e_data_cal_respond_authenticate_user (cal, opid, error);
+	e_cal_backend_notify_opened (backend, error);
 }
 
 static void
diff --git a/calendar/libedata-cal/e-cal-backend-sync.h b/calendar/libedata-cal/e-cal-backend-sync.h
index 17f6cca..a77dc87 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.h
+++ b/calendar/libedata-cal/e-cal-backend-sync.h
@@ -32,7 +32,6 @@ struct _ECalBackendSyncClass {
 
 	/* Virtual methods */
 	void	(* open_sync)			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **error);
-	void	(* authenticate_user_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error);
 	void	(* remove_sync)			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
 
 	void	(* refresh_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
@@ -50,6 +49,8 @@ struct _ECalBackendSyncClass {
 	void	(* discard_alarm_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid, GError **error);
 	void	(* get_timezone_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error);
 	void	(* add_timezone_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobject, GError **error);
+
+	void	(* authenticate_user_sync)	(ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 };
 
 GType	e_cal_backend_sync_get_type		(void);
@@ -57,7 +58,6 @@ GType	e_cal_backend_sync_get_type		(void);
 void	e_cal_backend_sync_set_lock		(ECalBackendSync *backend, gboolean lock);
 
 void	e_cal_backend_sync_open			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **error);
-void	e_cal_backend_sync_authenticate_user	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, ECredentials *credentials, GError **error);
 void	e_cal_backend_sync_remove		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
 void	e_cal_backend_sync_refresh		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
 gboolean e_cal_backend_sync_get_backend_property(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
@@ -75,6 +75,8 @@ void	e_cal_backend_sync_discard_alarm	(ECalBackendSync *backend, EDataCal *cal,
 void	e_cal_backend_sync_get_timezone		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error);
 void	e_cal_backend_sync_add_timezone		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobject, GError **error);
 
+void	e_cal_backend_sync_authenticate_user	(ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
+
 G_END_DECLS
 
 #endif /* __E_CAL_BACKEND_SYNC_H__ */
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 7823d58..3349770 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -31,6 +31,7 @@
 #include "e-cal-backend-cache.h"
 
 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
+#define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
 
 /* Private part of the CalBackend structure */
 struct _ECalBackendPrivate {
@@ -39,7 +40,7 @@ struct _ECalBackendPrivate {
 	/* The kind of components for this backend */
 	icalcomponent_kind kind;
 
-	gboolean loaded, readonly, removed, online;
+	gboolean opening, opened, readonly, removed, online;
 
 	/* URI, from source. This is cached, since we return const. */
 	gchar *uri;
@@ -192,8 +193,10 @@ cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 o
 	g_return_if_fail (cal != NULL);
 	g_return_if_fail (prop_name != NULL);
 
-	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_LOADED)) {
-		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_loaded (backend) ? "TRUE" : "FALSE");
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
 		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_online (backend) ? "TRUE" : "FALSE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
@@ -399,7 +402,6 @@ e_cal_backend_init (ECalBackend *backend)
 	backend->priv->views = NULL;
 	backend->priv->views_mutex = g_mutex_new ();
 
-	backend->priv->loaded = FALSE;
 	backend->priv->readonly = TRUE;
 	backend->priv->online = FALSE;
 }
@@ -468,32 +470,43 @@ e_cal_backend_is_online (ECalBackend *backend)
 }
 
 /**
- * e_cal_backend_is_loaded:
+ * e_cal_backend_is_opened:
  * @backend: an #ECalBackend
  *
- * Returns: Whether is backend already loaded.
+ * Checks if @backend's storage has been opened (and
+ * authenticated, if necessary) and the backend itself
+ * is ready for accessing. This property is changed automatically
+ * within call of e_cal_backend_notify_opened().
+ *
+ * Returns: %TRUE if fully opened, %FALSE otherwise.
  **/
 gboolean
-e_cal_backend_is_loaded (ECalBackend *backend)
+e_cal_backend_is_opened (ECalBackend *backend)
 {
 	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
 
-	return backend->priv->loaded;
+	return backend->priv->opened;
 }
 
 /**
- * e_cal_backend_set_is_loaded:
+ * e_cal_backend_is_opening::
  * @backend: an #ECalBackend
  *
- * Stores value for e_cal_backend_is_loaded().
- * Meant to be used by backend implementations.
+ * Checks if @backend is processing its opening phase, which
+ * includes everything since the e_cal_backend_open() call,
+ * through authentication, up to e_cal_backend_notify_opened().
+ * This property is managed automatically and the backend deny
+ * every operation except of cancel and authenticate_user while
+ * it is being opening.
+ *
+ * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
  **/
-void
-e_cal_backend_set_is_loaded (ECalBackend *backend, gboolean is_loaded)
+gboolean
+e_cal_backend_is_opening (ECalBackend *backend)
 {
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
 
-	backend->priv->loaded = is_loaded;
+	return backend->priv->opening;
 }
 
 /**
@@ -840,7 +853,50 @@ e_cal_backend_set_online (ECalBackend *backend, gboolean is_online)
  * does not exist.
  *
  * Opens a calendar backend with data from a calendar stored at the specified URI.
- * This might be finished with e_data_cal_respond_open().
+ * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
+ * though the overall opening phase finishes only after call
+ * of e_cal_backend_notify_opened() after which call the backend
+ * is either fully opened (including authentication against (remote)
+ * server/storage) or an error was encountered during this opening phase.
+ * 'opened' and 'opening' properties are updated automatically.
+ * The backend refuses all other operations until the opening phase is finished.
+ *
+ * The e_cal_backend_notify_opened() is called either from this function
+ * or from e_cal_backend_authenticate_user(), or after necessary steps
+ * initiated by these two functions.
+ *
+ * The opening phase usually works like this:
+ * 1) client requests open for the backend
+ * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
+ * 3) either the backend is opened during this call, and notifies client
+ *    with e_cal_backend_notify_opened() about that. This is usually
+ *    for local backends; their opening phase is finished
+ * 4) or the backend requires authentication, thus it notifies client
+ *    about that with e_cal_backend_notify_auth_required() and is
+ *    waiting for credentials, which will be received from client
+ *    by e_cal_backend_authenticate_user() call. Backend's opening
+ *    phase is still running in this case, thus it doesn't call
+ *    e_cal_backend_notify_opened() within e_cal_backend_open() call.
+ * 5) when backend receives credentials in e_cal_backend_authenticate_user()
+ *    then it tries to authenticate against a server/storage with them
+ *    and only after it knows result of the authentication, whether user
+ *    was or wasn't authenticated, it notifies client with the result
+ *    by e_cal_backend_notify_opened() and it's opening phase is
+ *    finished now. If there was no error returned then the backend is
+ *    considered opened, otherwise it's considered closed. Use AuthenticationFailed
+ *    error when the given credentials were rejected by the server/store, which
+ *    will result in a re-prompt on the client side, otherwise use AuthenticationRequired
+ *    if there was anything wrong with the given credentials. Set error's
+ *    message to a reason for a re-prompt, it'll be shown to a user.
+ * 6) client checks error returned from e_cal_backend_notify_opened() and
+ *    reprompts for a password if it was AuthenticationFailed. Otherwise
+ *    considers backend opened based on the error presence (no error means success).
+ *
+ * In any case, the call of e_cal_backend_open() should be always finished
+ * with e_data_cal_respond_open(), which has no influence on the opening phase,
+ * or alternatively with e_cal_backend_respond_opened(). Never use authentication
+ * errors in e_data_cal_respond_open() to notify the client the authentication is
+ * required, there is e_cal_backend_notify_auth_required() for this.
  **/
 void
 e_cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists)
@@ -849,35 +905,56 @@ e_cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancella
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
+	g_mutex_lock (backend->priv->clients_mutex);
+
+	if (e_cal_backend_is_opened (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
+
+		e_data_cal_report_readonly (cal, backend->priv->readonly);
+		e_data_cal_report_online (cal, backend->priv->online);
+
+		e_cal_backend_respond_opened (backend, cal, opid, NULL);
+	} else if (e_cal_backend_is_opening (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
+
+		e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
+	} else {
+		backend->priv->opening = TRUE;
+		g_mutex_unlock (backend->priv->clients_mutex);
+
+		(* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
+	}
 }
 
 /**
  * e_cal_backend_authenticate_user:
  * @backend: an #ECalBackend
- * @cal: an #EDataCal
- * @opid: the ID to use for this operation
  * @cancellable: a #GCancellable for the operation
- * @opid: the ID to use for this operation
  * @credentials: #ECredentials to use for authentication
  *
- * Executes an 'authenticate' request specified by @opid on @cal
- * using @backend.
- * This might be finished with e_data_cal_respond_authenticate_user().
+ * Notifies @backend about @credentials provided by user to use
+ * for authentication. This notification is usually called during
+ * opening phase as a response to e_cal_backend_notify_auth_required()
+ * on the client side and it results in setting property 'opening' to %TRUE
+ * unless the backend is already opened. This function finishes opening
+ * phase, thus it should be finished with e_cal_backend_notify_opened().
+ *
+ * See information at e_cal_backend_open() for more details
+ * how the opening phase works.
  **/
 void
 e_cal_backend_authenticate_user (ECalBackend  *backend,
-				 EDataCal     *cal,
-				 guint32       opid,
 				 GCancellable *cancellable,
 				 ECredentials *credentials)
 {
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_CAL (cal));
 	g_return_if_fail (credentials != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cal, opid, cancellable, credentials);
+	if (!e_cal_backend_is_opened (backend))
+		backend->priv->opening = TRUE;
+
+	(* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
 }
 
 /**
@@ -897,7 +974,10 @@ e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancel
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
 }
 
 /**
@@ -919,7 +999,10 @@ e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, guint32 opid, GCance
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->refresh != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
 }
 
 /**
@@ -943,7 +1026,10 @@ e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCa
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
 }
 
 /**
@@ -964,7 +1050,10 @@ e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, guint32 opid
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
 }
 
 /**
@@ -990,7 +1079,10 @@ e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, guint32 opid,
 	g_return_if_fail (start <= end);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
 }
 
 /**
@@ -1011,7 +1103,9 @@ e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, guint32 opid,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
 
-	if (E_CAL_BACKEND_GET_CLASS (backend)->create_object)
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->create_object)
 		(* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
 	else
 		e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
@@ -1036,7 +1130,9 @@ e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, guint32 opid,
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
 
-	if (E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
 		(* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
 	else
 		e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
@@ -1064,7 +1160,10 @@ e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, guint32 opid,
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
 }
 
 /**
@@ -1086,7 +1185,10 @@ e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, guint32 opid
 	g_return_if_fail (calobj != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
 }
 
 /**
@@ -1108,7 +1210,10 @@ e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, G
 	g_return_if_fail (calobj != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
 }
 
 /**
@@ -1132,7 +1237,10 @@ e_cal_backend_get_attachment_uris (ECalBackend *backend, EDataCal *cal, guint32
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
 }
 
 /**
@@ -1157,12 +1265,12 @@ e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, guint32 opid,
 	g_return_if_fail (uid != NULL);
 	g_return_if_fail (auid != NULL);
 
-	if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) {
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
+		(* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
+	else
 		e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
-		return;
-	}
-
-	(* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
 }
 
 /**
@@ -1186,7 +1294,10 @@ e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, G
 	g_return_if_fail (tzid != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
 }
 
 /**
@@ -1207,7 +1318,10 @@ e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, G
 	g_return_if_fail (tzobject != NULL);
 	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
 
-	(* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
 }
 
 /**
@@ -1555,15 +1669,27 @@ e_cal_backend_notify_online (ECalBackend *backend, gboolean is_online)
 /**
  * e_cal_backend_notify_auth_required:
  * @backend: an #ECalBackend
+ * @is_self: Use %TRUE to indicate the authentication is required
+ *    for the @backend, otheriwse the authentication is for any
+ *    other source. Having @credentials %NULL means @is_self
+ *    automatically.
  * @credentials: an #ECredentials that contains extra information for
  *    a source for which authentication is requested.
  *    This parameter can be NULL to indicate "for this calendar".
  *
  * Notifies clients that @backend requires authentication in order to
- * connect. Means to be used by backend implementations.
+ * connect. This function call does not influence 'opening', but 
+ * influences 'opened' property, which is set to %FALSE when @is_self
+ * is %TRUE or @credentials is %NULL. Opening phase is finished
+ * by e_cal_backend_notify_opened() if this is requested for @backend.
+ *
+ * See e_cal_backend_open() for a description how the whole opening
+ * phase works.
+ *
+ * Meant to be used by backend implementations.
  **/
 void
-e_cal_backend_notify_auth_required (ECalBackend *backend, const ECredentials *credentials)
+e_cal_backend_notify_auth_required (ECalBackend *backend, gboolean is_self, const ECredentials *credentials)
 {
 	ECalBackendPrivate *priv;
 	GSList *clients;
@@ -1571,12 +1697,15 @@ e_cal_backend_notify_auth_required (ECalBackend *backend, const ECredentials *cr
 	priv = backend->priv;
 
 	if (priv->notification_proxy) {
-		e_cal_backend_notify_auth_required (priv->notification_proxy, credentials);
+		e_cal_backend_notify_auth_required (priv->notification_proxy, is_self, credentials);
 		return;
 	}
 
 	g_mutex_lock (priv->clients_mutex);
 
+	if (is_self || !credentials)
+		priv->opened = FALSE;
+
 	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
 		e_data_cal_report_auth_required (E_DATA_CAL (clients->data), credentials);
 
@@ -1584,6 +1713,77 @@ e_cal_backend_notify_auth_required (ECalBackend *backend, const ECredentials *cr
 }
 
 /**
+ * e_cal_backend_notify_opened:
+ * @backend: an #ECalBackend
+ * @error: a #GError corresponding to the error encountered during
+ *    the opening phase. Use %NULL for success. The @error is freed
+ *    automatically if not %NULL.
+ *
+ * Notifies clients that @backend finished its opening phase.
+ * See e_cal_backend_open() for more information how the opening
+ * phase works. Calling this function changes 'opening' property,
+ * same as 'opened'. 'opening' is set to %FALSE and the backend
+ * is considered 'opened' only if the @error is %NULL.
+ *
+ * See also: e_cal_backend_respond_opened()
+ *
+ * Note: The @error is freed automatically if not %NULL.
+ *
+ * Meant to be used by backend implementations.
+ **/
+void
+e_cal_backend_notify_opened (ECalBackend *backend, GError *error)
+{
+	ECalBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+	g_mutex_lock (priv->clients_mutex);
+
+	priv->opening = FALSE;
+	priv->opened = error == NULL;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
+
+	g_mutex_unlock (priv->clients_mutex);
+
+	if (error)
+		g_error_free (error);
+}
+
+/**
+ * e_cal_backend_respond_opened:
+ * @backend: an #ECalBackend
+ * @cal: an #EDataCal
+ * @opid: an operation ID
+ * @error: result error; can be %NULL, if it isn't then it's automatically freed
+ *
+ * This is a replacement for e_data_cal_respond_open() for cases where
+ * the finish of 'open' method call also finishes backend opening phase.
+ * This function covers calling of both e_data_cal_respond_open() and
+ * e_cal_backend_notify_opened() with the same @error.
+ *
+ * See e_cal_backend_open() for more details how the opening phase works.
+ **/
+void
+e_cal_backend_respond_opened (ECalBackend *backend, EDataCal *cal, guint32 opid, GError *error)
+{
+	GError *copy = NULL;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (cal != NULL);
+	g_return_if_fail (opid != 0);
+
+	if (error)
+		copy = g_error_copy (error);
+
+	e_data_cal_respond_open (cal, opid, error);
+	e_cal_backend_notify_opened (backend, copy);
+}
+
+/**
  * e_cal_backend_empty_cache:
  * @backend: an #ECalBackend
  * @cache: Backend's cache to empty.
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index 5b33152..360c4e4 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -43,7 +43,8 @@ G_BEGIN_DECLS
 #define E_IS_CAL_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND))
 #define E_CAL_BACKEND_GET_CLASS(obj)  (E_CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (obj)))
 
-#define CLIENT_BACKEND_PROPERTY_LOADED			"loaded"
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
 #define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
 #define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
 #define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
@@ -70,9 +71,9 @@ struct _ECalBackendClass {
         void	(* set_backend_property)	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
 
 	void	(* open)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
-	void	(* authenticate_user)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, ECredentials *credentials);
 	void	(* remove)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
 	void	(* set_online)			(ECalBackend *backend, gboolean is_online);
+	void	(* authenticate_user)		(ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials);
 
 	void	(* refresh)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
 	void	(* get_object)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
@@ -104,7 +105,8 @@ ESource *	e_cal_backend_get_source		(ECalBackend *backend);
 const gchar *	e_cal_backend_get_uri			(ECalBackend *backend);
 icalcomponent_kind e_cal_backend_get_kind		(ECalBackend *backend);
 gboolean	e_cal_backend_is_online			(ECalBackend *backend);
-gboolean	e_cal_backend_is_loaded			(ECalBackend *backend);
+gboolean	e_cal_backend_is_opened			(ECalBackend *backend);
+gboolean	e_cal_backend_is_opening		(ECalBackend *backend);
 gboolean	e_cal_backend_is_readonly		(ECalBackend *backend);
 gboolean	e_cal_backend_is_removed		(ECalBackend *backend);
 
@@ -124,8 +126,9 @@ void		e_cal_backend_get_backend_property	(ECalBackend *backend, EDataCal *cal, g
 void		e_cal_backend_set_backend_property	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
 
 void		e_cal_backend_set_online		(ECalBackend *backend, gboolean is_online);
+void		e_cal_backend_authenticate_user		(ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials);
+
 void		e_cal_backend_open			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
-void		e_cal_backend_authenticate_user		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, ECredentials *credentials);
 void		e_cal_backend_remove			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
 void		e_cal_backend_refresh			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
 void		e_cal_backend_get_object		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
@@ -154,14 +157,16 @@ void		e_cal_backend_notify_objects_removed	(ECalBackend *backend, EDataCalView *
 void		e_cal_backend_notify_error		(ECalBackend *backend, const gchar *message);
 void		e_cal_backend_notify_readonly		(ECalBackend *backend, gboolean is_readonly);
 void		e_cal_backend_notify_online		(ECalBackend *backend, gboolean is_online);
-void		e_cal_backend_notify_auth_required	(ECalBackend *backend, const ECredentials *credentials);
+void		e_cal_backend_notify_auth_required	(ECalBackend *backend, gboolean is_self, const ECredentials *credentials);
+void		e_cal_backend_notify_opened		(ECalBackend *backend, GError *error);
 
 void		e_cal_backend_empty_cache		(ECalBackend *backend, struct _ECalBackendCache *cache);
 
 /* protected functions for subclasses */
-void		e_cal_backend_set_is_loaded		(ECalBackend *backend, gboolean is_loaded);
 void		e_cal_backend_set_is_removed		(ECalBackend *backend, gboolean is_removed);
 
+void		e_cal_backend_respond_opened		(ECalBackend *backend, EDataCal *cal, guint32 opid, GError *error);
+
 G_END_DECLS
 
 #endif
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index 15bc734..e43b452 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -353,12 +353,6 @@ impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocat
 	gchar *source_xml = NULL;
 	guint type = 0;
 
-	/* Remove a pending exit */
-	if (priv->exit_timeout) {
-		g_source_remove (priv->exit_timeout);
-		priv->exit_timeout = 0;
-	}
-
 	if (!e_gdbus_cal_factory_decode_get_cal (in_source_type, &source_xml, &type)) {
 		error = g_error_new (E_DATA_CAL_ERROR, NoSuchCal, _("Invalid call"));
 		g_dbus_method_invocation_return_gerror (invocation, error);
@@ -497,6 +491,12 @@ impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocat
 		update_source_in_backend (backend, source);
 	}
 
+	/* Remove a pending exit */
+	if (priv->exit_timeout) {
+		g_source_remove (priv->exit_timeout);
+		priv->exit_timeout = 0;
+	}
+
 	calendar = e_data_cal_new (backend, source);
 	e_cal_backend_add_client (backend, calendar);
 
diff --git a/calendar/libedata-cal/e-data-cal-types.h b/calendar/libedata-cal/e-data-cal-types.h
index e2b47ed..d4f75f4 100644
--- a/calendar/libedata-cal/e-data-cal-types.h
+++ b/calendar/libedata-cal/e-data-cal-types.h
@@ -6,6 +6,7 @@ G_BEGIN_DECLS
 
 typedef enum {
 	Success,
+	Busy,
 	RepositoryOffline,
 	PermissionDenied,
 	InvalidRange,
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 0fb7d52..3a9ea41 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -335,7 +335,7 @@ notify_complete (EDataCalView *view, const GError *error)
 	send_pending_changes (view);
 	send_pending_removes (view);
 
-	error_strv = e_gdbus_cal_view_encode_error (error);
+	error_strv = e_gdbus_templates_encode_error (error);
 
 	e_gdbus_cal_view_emit_complete (view->priv->gdbus_object, (const gchar * const *) error_strv);
 
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index c8f8292..8f32133 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -178,10 +178,6 @@ operation_thread (gpointer data, gpointer user_data)
 	case OP_OPEN:
 		e_cal_backend_open (backend, op->cal, op->id, op->cancellable, op->d.only_if_exists);
 		break;
-	case OP_AUTHENTICATE:
-		e_cal_backend_authenticate_user (backend, op->cal, op->id, op->cancellable, op->d.credentials);
-		e_credentials_free (op->d.credentials);
-		break;
 	case OP_REMOVE:
 		e_cal_backend_remove (backend, op->cal, op->id, op->cancellable);
 		break;
@@ -298,6 +294,10 @@ operation_thread (gpointer data, gpointer user_data)
 		e_cal_backend_add_timezone (backend, op->cal, op->id, op->cancellable, op->d.tzobject);
 		g_free (op->d.tzobject);
 		break;
+	case OP_AUTHENTICATE:
+		e_cal_backend_authenticate_user (backend, op->cancellable, op->d.credentials);
+		e_credentials_free (op->d.credentials);
+		break;
 	case OP_CANCEL_OPERATION:
 		g_static_rec_mutex_lock (&op->cal->priv->pending_ops_lock);
 
@@ -362,6 +362,7 @@ e_data_cal_error_quark (void)
 
 	static const GDBusErrorEntry entries[] = {
 		{ Success,				ERR_PREFIX "Success" },
+		{ Busy,					ERR_PREFIX "Busy" },
 		{ RepositoryOffline,			ERR_PREFIX "RepositoryOffline" },
 		{ PermissionDenied,			ERR_PREFIX "PermissionDenied" },
 		{ InvalidRange,				ERR_PREFIX "InvalidRange" },
@@ -411,6 +412,7 @@ e_data_cal_status_to_string (EDataCalCallStatus status)
 		const gchar *msg;
 	} statuses[] = {
 		{ Success,				N_("Success") },
+		{ Busy,					N_("Backend is busy") },
 		{ RepositoryOffline,			N_("Repository offline") },
 		{ PermissionDenied,			N_("Permission denied") },
 		{ InvalidRange,				N_("Invalid range") },
@@ -569,28 +571,6 @@ impl_Cal_open (EGdbusCal *object, GDBusMethodInvocation *invocation, gboolean in
 }
 
 static gboolean
-impl_Cal_authenticateUser (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataCal *cal)
-{
-	OperationData *op;
-
-	if (in_credentials == NULL) {
-		GError *error = e_data_cal_create_error (InvalidArg, NULL);
-		/* Translators: This is prefix to a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot authenticate user: "));
-		g_error_free (error);
-		return TRUE;
-	}
-
-	op = op_new (OP_AUTHENTICATE, cal);
-	op->d.credentials = e_credentials_new_strv (in_credentials);
-
-	e_gdbus_cal_complete_authenticate_user (cal->priv->gdbus_object, invocation, op->id);
-	e_operation_pool_push (ops_pool, op);
-
-	return TRUE;
-}
-
-static gboolean
 impl_Cal_remove (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
 {
 	OperationData *op;
@@ -835,6 +815,28 @@ impl_Cal_addTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, cons
 }
 
 static gboolean
+impl_Cal_authenticateUser (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataCal *cal)
+{
+	OperationData *op;
+
+	if (in_credentials == NULL) {
+		GError *error = e_data_cal_create_error (InvalidArg, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_cal_return_error (invocation, error, _("Cannot authenticate user: "));
+		g_error_free (error);
+		return TRUE;
+	}
+
+	op = op_new (OP_AUTHENTICATE, cal);
+	op->d.credentials = e_credentials_new_strv (in_credentials);
+
+	e_gdbus_cal_complete_authenticate_user (cal->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
+}
+
+static gboolean
 impl_Cal_cancelOperation (EGdbusCal *object, GDBusMethodInvocation *invocation, guint in_opid, EDataCal *cal)
 {
 	OperationData *op;
@@ -913,20 +915,6 @@ e_data_cal_respond_open (EDataCal *cal, guint32 opid, GError *error)
 		g_error_free (error);
 }
 
-void
-e_data_cal_respond_authenticate_user (EDataCal *cal, guint32 opid, GError *error)
-{
-	op_complete (cal, opid);
-
-	/* Translators: This is prefix to a detailed error message */
-	g_prefix_error (&error, "%s", _("Cannot authenticate user: "));
-
-	e_gdbus_cal_emit_authenticate_user_done (cal->priv->gdbus_object, opid, error);
-
-	if (error)
-		g_error_free (error);
-}
-
 /**
  * e_data_cal_respond_remove:
  * @cal: A calendar client interface.
@@ -1391,6 +1379,23 @@ e_data_cal_report_auth_required (EDataCal *cal, const ECredentials *credentials)
 	g_strfreev (strv);
 }
 
+/* Reports to associated client that opening phase of the cal is finished.
+   error being NULL means successfully, otherwise reports an error which happened
+   during opening phase. By opening phase is meant a process including successfull
+   authentication to the server/storage.
+*/
+void
+e_data_cal_report_opened (EDataCal *cal, const GError *error)
+{
+	gchar **strv_error;
+
+	strv_error = e_gdbus_templates_encode_error (error);
+
+	e_gdbus_cal_emit_opened (cal->priv->gdbus_object, (const gchar * const *) strv_error);
+
+	g_strfreev (strv_error);
+}
+
 void
 e_data_cal_report_free_busy_data (EDataCal *cal, const GSList *freebusy)
 {
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 3a538ef..9d8b553 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -131,7 +131,6 @@ ESource *	e_data_cal_get_source				(EDataCal *cal);
 guint		e_data_cal_register_gdbus_object		(EDataCal *cal, GDBusConnection *connection, const gchar *object_path, GError **error);
 
 void		e_data_cal_respond_open				(EDataCal *cal, guint32 opid, GError *error);
-void		e_data_cal_respond_authenticate_user		(EDataCal *cal, guint32 opid, GError *error);
 void		e_data_cal_respond_remove			(EDataCal *cal, guint32 opid, GError *error);
 void		e_data_cal_respond_refresh			(EDataCal *cal, guint32 opid, GError *error);
 void		e_data_cal_respond_get_backend_property		(EDataCal *cal, guint32 opid, GError *error, const gchar *prop_value);
@@ -154,6 +153,7 @@ void		e_data_cal_report_error				(EDataCal *cal, const gchar *message);
 void		e_data_cal_report_readonly			(EDataCal *cal, gboolean is_readonly);
 void		e_data_cal_report_online			(EDataCal *cal, gboolean is_online);
 void		e_data_cal_report_auth_required			(EDataCal *cal, const ECredentials *credentials);
+void		e_data_cal_report_opened			(EDataCal *cal, const GError *error);
 void		e_data_cal_report_free_busy_data		(EDataCal *cal, const GSList *freebusy);
 
 G_END_DECLS
diff --git a/calendar/libegdbus/e-gdbus-cal-view.c b/calendar/libegdbus/e-gdbus-cal-view.c
index 1497a98..be0eb1c 100644
--- a/calendar/libegdbus/e-gdbus-cal-view.c
+++ b/calendar/libegdbus/e-gdbus-cal-view.c
@@ -210,50 +210,6 @@ e_gdbus_cal_view_emit_progress (EGdbusCalView *object, guint arg_percent, const
 	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
 }
 
-/* free returned pointer with g_strfreev() */
-gchar **
-e_gdbus_cal_view_encode_error (const GError *in_error)
-{
-	gchar **strv;
-
-	strv = g_new0 (gchar *, 3);
-
-	if (!in_error) {
-		strv[0] = g_strdup ("");
-		strv[1] = g_strdup ("");
-	} else {
-		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
-
-		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
-		strv[1] = e_util_utf8_make_valid (in_error->message);
-
-		g_free (dbus_error_name);
-	}
-
-	return strv;
-}
-
-/* free returned pointer with g_error_free(), of not NULL */
-GError *
-e_gdbus_cal_view_decode_error (const gchar * const *in_strv)
-{
-	GError *error = NULL;
-	const gchar *error_name, *error_message;
-
-	g_return_val_if_fail (in_strv != NULL, NULL);
-	g_return_val_if_fail (in_strv[0] != NULL, NULL);
-	g_return_val_if_fail (in_strv[1] != NULL, NULL);
-	g_return_val_if_fail (in_strv[2] == NULL, NULL);
-
-	error_name = in_strv[0];
-	error_message = in_strv[1];
-
-	if (error_name && *error_name && error_message)
-		error = g_dbus_error_new_for_dbus_error (error_name, error_message);
-
-	return error;
-}
-
 void
 e_gdbus_cal_view_emit_complete (EGdbusCalView *object, const gchar * const *arg_error)
 {
diff --git a/calendar/libegdbus/e-gdbus-cal-view.h b/calendar/libegdbus/e-gdbus-cal-view.h
index c5a646c..fa2751b 100644
--- a/calendar/libegdbus/e-gdbus-cal-view.h
+++ b/calendar/libegdbus/e-gdbus-cal-view.h
@@ -140,9 +140,6 @@ void e_gdbus_cal_view_emit_objects_modified	(EGdbusCalView *object, const gchar
 void e_gdbus_cal_view_emit_objects_removed	(EGdbusCalView *object, const gchar * const *arg_uids);
 
 void e_gdbus_cal_view_emit_progress		(EGdbusCalView *object, guint arg_percent, const gchar *arg_message);
-
-gchar **e_gdbus_cal_view_encode_error		(const GError *in_error);
-GError *e_gdbus_cal_view_decode_error		(const gchar * const *in_strv);
 void e_gdbus_cal_view_emit_complete		(EGdbusCalView *object, const gchar * const *arg_error);
 
 G_END_DECLS
diff --git a/calendar/libegdbus/e-gdbus-cal.c b/calendar/libegdbus/e-gdbus-cal.c
index 54a89e0..3604be0 100644
--- a/calendar/libegdbus/e-gdbus-cal.c
+++ b/calendar/libegdbus/e-gdbus-cal.c
@@ -40,11 +40,10 @@ enum
 	__READONLY_SIGNAL,
 	__ONLINE_SIGNAL,
 	__AUTH_REQUIRED_SIGNAL,
+	__OPENED_SIGNAL,
 	__FREE_BUSY_DATA_SIGNAL,
 	__OPEN_METHOD,
 	__OPEN_DONE_SIGNAL,
-	__AUTHENTICATE_USER_METHOD,
-	__AUTHENTICATE_USER_DONE_SIGNAL,
 	__REMOVE_METHOD,
 	__REMOVE_DONE_SIGNAL,
 	__REFRESH_METHOD,
@@ -79,6 +78,7 @@ enum
 	__GET_TIMEZONE_DONE_SIGNAL,
 	__ADD_TIMEZONE_METHOD,
 	__ADD_TIMEZONE_DONE_SIGNAL,
+	__AUTHENTICATE_USER_METHOD,
 	__CANCEL_OPERATION_METHOD,
 	__CANCEL_ALL_METHOD,
 	__CLOSE_METHOD,
@@ -131,10 +131,10 @@ E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRING  (GDBUS_CAL_INTERFACE_NAME, backend_
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_CAL_INTERFACE_NAME, readonly)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_CAL_INTERFACE_NAME, online)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, auth_required)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, opened)
 E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, free_busy_data)
 
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, open)
-E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, authenticate_user)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, remove)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, refresh)
 E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, get_backend_property)
@@ -167,11 +167,11 @@ e_gdbus_cal_default_init (EGdbusCalIface *iface)
 	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusCalIface, "readonly",		readonly,	__READONLY_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusCalIface, "online",		online,		__ONLINE_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "auth_required", 	auth_required,	__AUTH_REQUIRED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "opened", 		opened,		__OPENED_SIGNAL)
 	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "free_busy_data", 	free_busy_data,	__FREE_BUSY_DATA_SIGNAL)
 
 	/* GObject signals definitions for D-Bus methods: */
 	E_INIT_GDBUS_METHOD_ASYNC_BOOLEAN__VOID	(EGdbusCalIface, "open",			open, __OPEN_METHOD, __OPEN_DONE_SIGNAL)
-	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD, __AUTHENTICATE_USER_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusCalIface, "remove",			remove, __REMOVE_METHOD, __REMOVE_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusCalIface, "refresh",			refresh, __REFRESH_METHOD, __REFRESH_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getBackendProperty",		get_backend_property, __GET_BACKEND_PROPERTY_METHOD, __GET_BACKEND_PROPERTY_DONE_SIGNAL)
@@ -189,6 +189,7 @@ e_gdbus_cal_default_init (EGdbusCalIface *iface)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getView",			get_view, __GET_VIEW_METHOD, __GET_VIEW_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getTimezone",			get_timezone, __GET_TIMEZONE_METHOD, __GET_TIMEZONE_DONE_SIGNAL)
 	E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID	(EGdbusCalIface, "addTimezone",			add_timezone, __ADD_TIMEZONE_METHOD, __ADD_TIMEZONE_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_STRV		(EGdbusCalIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD)
 	E_INIT_GDBUS_METHOD_UINT		(EGdbusCalIface, "cancelOperation",		cancel_operation, __CANCEL_OPERATION_METHOD)
 	E_INIT_GDBUS_METHOD_VOID		(EGdbusCalIface, "cancelAll",			cancel_all, __CANCEL_ALL_METHOD)
 	E_INIT_GDBUS_METHOD_VOID		(EGdbusCalIface, "close",			close, __CLOSE_METHOD)
@@ -244,26 +245,6 @@ e_gdbus_cal_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCanc
 }
 
 void
-e_gdbus_cal_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
-{
-	e_gdbus_proxy_call_strv ("authenticateUser", e_gdbus_cal_call_authenticate_user, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_credentials, cancellable, callback, user_data);
-}
-
-gboolean
-e_gdbus_cal_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
-{
-	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_authenticate_user);
-}
-
-gboolean
-e_gdbus_cal_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
-{
-	return e_gdbus_proxy_call_sync_strv__void (proxy, in_credentials, cancellable, error,
-		e_gdbus_cal_call_authenticate_user,
-		e_gdbus_cal_call_authenticate_user_finish);
-}
-
-void
 e_gdbus_cal_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
 	e_gdbus_proxy_call_void ("remove", e_gdbus_cal_call_remove, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
@@ -841,6 +822,24 @@ e_gdbus_cal_call_add_timezone_sync (GDBusProxy *proxy, const gchar *in_tzobject,
 }
 
 void
+e_gdbus_cal_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("authenticateUser", proxy, in_credentials, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("authenticateUser", proxy, in_credentials, cancellable, error);
+}
+
+void
 e_gdbus_cal_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
 	e_gdbus_proxy_method_call_uint ("cancelOperation", proxy, in_opid, cancellable, callback, user_data);
@@ -909,7 +908,6 @@ e_gdbus_cal_emit_ ## _mname ## _done (EGdbusCal *object, guint arg_opid, const G
 }
 
 DECLARE_EMIT_DONE_SIGNAL_0 (open,			__OPEN_DONE_SIGNAL)
-DECLARE_EMIT_DONE_SIGNAL_0 (authenticate_user,		__AUTHENTICATE_USER_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_0 (remove,			__REMOVE_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_0 (refresh,			__REFRESH_DONE_SIGNAL)
 DECLARE_EMIT_DONE_SIGNAL_1 (get_backend_property,	__GET_BACKEND_PROPERTY_DONE_SIGNAL, const gchar *)
@@ -956,6 +954,12 @@ e_gdbus_cal_emit_auth_required (EGdbusCal *object, const gchar * const *arg_cred
 }
 
 void
+e_gdbus_cal_emit_opened (EGdbusCal *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__OPENED_SIGNAL], 0, arg_error);
+}
+
+void
 e_gdbus_cal_emit_free_busy_data (EGdbusCal *object, const gchar * const *arg_free_busy)
 {
 	g_signal_emit (object, signals[__FREE_BUSY_DATA_SIGNAL], 0, arg_free_busy);
@@ -965,10 +969,10 @@ E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, backend_error, message, "s")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, readonly, is_readonly, "b")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, online, is_online, "b")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, auth_required, credentials, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, opened, error, "as")
 E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, free_busy_data, free_busy_data, "as")
 
 E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, open, only_if_exists, "b")
-E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, authenticateUser, credentials, "as")
 E_DECLARE_GDBUS_ASYNC_METHOD_0			(cal, remove)
 E_DECLARE_GDBUS_ASYNC_METHOD_0			(cal, refresh)
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getBackendProperty, propname, "s", propvalue, "s")
@@ -987,6 +991,7 @@ E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getView, sexp, "s", view_path,
 E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getTimezone, tzid, "s", tzobject, "s")
 E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, addTimezone, tzobject, "s")
 
+E_DECLARE_GDBUS_SYNC_METHOD_1			(cal, authenticateUser, credentials, "as")
 E_DECLARE_GDBUS_SYNC_METHOD_1			(cal, cancelOperation, opid, "u")
 E_DECLARE_GDBUS_SYNC_METHOD_0			(cal, cancelAll)
 E_DECLARE_GDBUS_SYNC_METHOD_0			(cal, close)
@@ -994,7 +999,6 @@ E_DECLARE_GDBUS_SYNC_METHOD_0			(cal, close)
 static const GDBusMethodInfo * const e_gdbus_cal_method_info_pointers[] =
 {
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, open),
-	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, authenticateUser),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, remove),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, refresh),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getBackendProperty),
@@ -1012,6 +1016,7 @@ static const GDBusMethodInfo * const e_gdbus_cal_method_info_pointers[] =
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getView),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getTimezone),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, addTimezone),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, authenticateUser),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, cancelOperation),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, cancelAll),
 	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, close),
@@ -1024,10 +1029,10 @@ static const GDBusSignalInfo * const e_gdbus_cal_signal_info_pointers[] =
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, readonly),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, online),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, auth_required),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, opened),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, free_busy_data),
 
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, open_done),
-	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, authenticateUser_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, remove_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, refresh_done),
 	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getBackendProperty_done),
@@ -1251,7 +1256,6 @@ e_gdbus_cal_proxy_init (EGdbusCalProxy *proxy)
 	proxy->priv->pending_ops = e_gdbus_async_op_keeper_create_pending_ops (E_GDBUS_ASYNC_OP_KEEPER (proxy));
 
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (open);
-	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (authenticate_user);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (refresh);
 	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_backend_property);
diff --git a/calendar/libegdbus/e-gdbus-cal.h b/calendar/libegdbus/e-gdbus-cal.h
index 79bbb90..21e2c7d 100644
--- a/calendar/libegdbus/e-gdbus-cal.h
+++ b/calendar/libegdbus/e-gdbus-cal.h
@@ -107,15 +107,13 @@ struct _EGdbusCalIface
 	void	(*readonly)				(EGdbusCal *object, gboolean arg_is_readonly);
 	void	(*online)				(EGdbusCal *object, gboolean arg_is_online);
 	void	(*auth_required)			(EGdbusCal *object, const gchar * const *arg_credentials);
+	void	(*opened)				(EGdbusCal *object, const gchar * const *arg_error);
 	void	(*free_busy_data)			(EGdbusCal *object, const gchar * const *arg_free_busy);
 
 	/* Signal handlers for handling D-Bus method calls: */
 	gboolean (*handle_open)				(EGdbusCal *object, GDBusMethodInvocation *invocation, gboolean in_only_if_exists);
 	void	 (*open_done)				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
-	gboolean (*handle_authenticate_user)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
-	void	 (*authenticate_user_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
-
 	gboolean (*handle_remove)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
 	void	 (*remove_done)				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
@@ -167,6 +165,7 @@ struct _EGdbusCalIface
 	gboolean (*handle_add_timezone)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_tzobject);
 	void	 (*add_timezone_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 
+	gboolean (*handle_authenticate_user)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
 	gboolean (*handle_cancel_operation)		(EGdbusCal *object, GDBusMethodInvocation *invocation, guint in_opid);
 	gboolean (*handle_cancel_all)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
 	gboolean (*handle_close)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
@@ -177,10 +176,6 @@ void		e_gdbus_cal_call_open				(GDBusProxy *proxy, gboolean in_only_if_exists, G
 gboolean	e_gdbus_cal_call_open_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_cal_call_open_sync			(GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error);
 
-void		e_gdbus_cal_call_authenticate_user		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean	e_gdbus_cal_call_authenticate_user_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
-gboolean	e_gdbus_cal_call_authenticate_user_sync		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
-
 void		e_gdbus_cal_call_remove				(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean	e_gdbus_cal_call_remove_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_cal_call_remove_sync			(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
@@ -265,6 +260,10 @@ void		e_gdbus_cal_call_add_timezone			(GDBusProxy *proxy, const gchar *in_tzobje
 gboolean	e_gdbus_cal_call_add_timezone_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_cal_call_add_timezone_sync		(GDBusProxy *proxy, const gchar *in_tzobject, GCancellable *cancellable, GError **error);
 
+void		e_gdbus_cal_call_authenticate_user		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_authenticate_user_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_authenticate_user_sync		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
+
 void		e_gdbus_cal_call_cancel_operation		(GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
 gboolean	e_gdbus_cal_call_cancel_operation_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
 gboolean	e_gdbus_cal_call_cancel_operation_sync		(GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error);
@@ -279,7 +278,6 @@ gboolean	e_gdbus_cal_call_close_sync			(GDBusProxy *proxy, GCancellable *cancell
 
 /* D-Bus Methods Completion Helpers */
 #define e_gdbus_cal_complete_open			e_gdbus_complete_async_method
-#define e_gdbus_cal_complete_authenticate_user		e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_remove			e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_refresh			e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_get_backend_property	e_gdbus_complete_async_method
@@ -297,12 +295,12 @@ gboolean	e_gdbus_cal_call_close_sync			(GDBusProxy *proxy, GCancellable *cancell
 #define e_gdbus_cal_complete_get_view			e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_get_timezone		e_gdbus_complete_async_method
 #define e_gdbus_cal_complete_add_timezone		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_authenticate_user		e_gdbus_complete_sync_method_void
 #define e_gdbus_cal_complete_cancel_operation		e_gdbus_complete_sync_method_void
 #define e_gdbus_cal_complete_cancel_all			e_gdbus_complete_sync_method_void
 #define e_gdbus_cal_complete_close			e_gdbus_complete_sync_method_void
 
 void e_gdbus_cal_emit_open_done				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
-void e_gdbus_cal_emit_authenticate_user_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_remove_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_refresh_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
 void e_gdbus_cal_emit_get_backend_property_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_prop_value);
@@ -327,6 +325,7 @@ void e_gdbus_cal_emit_backend_error	(EGdbusCal *object, const gchar *arg_message
 void e_gdbus_cal_emit_readonly		(EGdbusCal *object, gboolean arg_is_readonly);
 void e_gdbus_cal_emit_online		(EGdbusCal *object, gint arg_is_online);
 void e_gdbus_cal_emit_auth_required	(EGdbusCal *object, const gchar * const *arg_credentials);
+void e_gdbus_cal_emit_opened		(EGdbusCal *object, const gchar * const *arg_error);
 void e_gdbus_cal_emit_free_busy_data	(EGdbusCal *object, const gchar * const *arg_free_busy);
 
 G_END_DECLS
diff --git a/libedataserver/e-client-private.h b/libedataserver/e-client-private.h
index d32522d..71091bf 100644
--- a/libedataserver/e-client-private.h
+++ b/libedataserver/e-client-private.h
@@ -40,6 +40,7 @@ void		e_client_unregister_op		(EClient *client, guint32 opid);
 void		e_client_process_authentication	(EClient *client, const ECredentials *credentials);
 
 gboolean	e_client_emit_authenticate	(EClient *client, ECredentials *credentials);
+void		e_client_emit_opened		(EClient *client, const GError *error);
 void		e_client_emit_backend_error	(EClient *client, const gchar *error_msg);
 void		e_client_emit_backend_died	(EClient *client);
 
diff --git a/libedataserver/e-client.c b/libedataserver/e-client.c
index 4e11710..1479a13 100644
--- a/libedataserver/e-client.c
+++ b/libedataserver/e-client.c
@@ -61,6 +61,7 @@ enum {
 
 enum {
 	AUTHENTICATE,
+	OPENED,
 	BACKEND_ERROR,
 	BACKEND_DIED,
 	LAST_SIGNAL
@@ -73,8 +74,10 @@ G_DEFINE_ABSTRACT_TYPE (EClient, e_client, G_TYPE_OBJECT)
 
 /**
  * Well-known client backend properties, which are common for each #EClient:
- * @CLIENT_BACKEND_PROPERTY_LOADED: Is set to "TRUE" or "FALSE" depending
- *   on the backend's loaded state.
+ * @CLIENT_BACKEND_PROPERTY_OPENED: Is set to "TRUE" or "FALSE" depending
+ *   whether the backend is fully opened.
+ * @CLIENT_BACKEND_PROPERTY_OPENING: Is set to "TRUE" or "FALSE" depending
+ *   whether the backend is processing its opening phase.
  * @CLIENT_BACKEND_PROPERTY_ONLINE: Is set to "TRUE" or "FALSE" depending
  *   on the backend's loaded state. See also e_client_is_online().
  * @CLIENT_BACKEND_PROPERTY_READONLY: Is set to "TRUE" or "FALSE" depending
@@ -325,6 +328,17 @@ e_client_class_init (EClientClass *klass)
 		G_TYPE_BOOLEAN, 1,
 		G_TYPE_POINTER);
 
+	signals[OPENED] = g_signal_new (
+		"opened",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EClientClass, opened),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__BOXED,
+		G_TYPE_NONE, 1,
+		G_TYPE_ERROR);
+
+
 	signals[BACKEND_ERROR] = g_signal_new (
 		"backend-error",
 		G_OBJECT_CLASS_TYPE (klass),
@@ -370,8 +384,15 @@ client_operation_thread (gpointer data, gpointer user_data)
 
 	switch (op_data->op) {
 	case E_CLIENT_OP_AUTHENTICATE:
-		if (e_client_emit_authenticate (op_data->client, op_data->d.credentials))
+		if (e_client_emit_authenticate (op_data->client, op_data->d.credentials)) {
 			client_handle_authentication (op_data->client, op_data->d.credentials);
+		} else {
+			GError *error;
+
+			error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED, e_client_error_to_string (E_CLIENT_ERROR_AUTHENTICATION_REQUIRED));
+			e_client_emit_opened (op_data->client, error);
+			g_error_free (error);
+		}
 		e_credentials_free (op_data->d.credentials);
 		break;
 	}
@@ -643,9 +664,13 @@ e_client_set_online (EClient *client, gboolean is_online)
  * e_client_is_opened:
  * @client: an #EClient
  *
- * Check if this @client has been opened.
+ * Check if this @client is fully opened. This includes
+ * everything from e_client_open() call up to the authentication,
+ * if required by a backend. Client cannot do any other operation
+ * during the opening phase except of authenticate or cancel it.
+ * Every other operation results in an %E_CLIENT_ERROR_BUSY error.
  *
- * Returns: %TRUE if this @client has been opened, otherwise %FALSE.
+ * Returns: %TRUE if this @client is fully opened, otherwise %FALSE.
  *
  * Since: 3.2.
  **/
@@ -831,6 +856,28 @@ e_client_emit_authenticate (EClient *client, ECredentials *credentials)
 }
 
 void
+e_client_emit_opened (EClient *client, const GError *dbus_error)
+{
+	GError *local_error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	client->priv->opened = dbus_error == NULL;
+
+	if (dbus_error) {
+		local_error = g_error_copy (dbus_error);
+		e_client_unwrap_dbus_error (client, local_error, &local_error);
+	}
+
+	g_signal_emit (client, signals[OPENED], 0, local_error);
+
+	if (local_error)
+		g_error_free (local_error);
+}
+
+void
 e_client_emit_backend_error (EClient *client, const gchar *error_msg)
 {
 	g_return_if_fail (client != NULL);
@@ -1084,7 +1131,6 @@ gboolean
 e_client_open_finish (EClient *client, GAsyncResult *result, GError **error)
 {
 	EClientClass *klass;
-	gboolean res;
 
 	g_return_val_if_fail (client != NULL, FALSE);
 	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
@@ -1094,11 +1140,7 @@ e_client_open_finish (EClient *client, GAsyncResult *result, GError **error)
 	g_return_val_if_fail (klass != NULL, FALSE);
 	g_return_val_if_fail (klass->open_finish != NULL, FALSE);
 
-	res = klass->open_finish (client, result, error);
-
-	client->priv->opened = res;
-
-	return res;
+	return klass->open_finish (client, result, error);
 }
 
 /**
@@ -1118,17 +1160,12 @@ gboolean
 e_client_open_sync (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error)
 {
 	EClientClass *klass;
-	gboolean res;
 
 	klass = E_CLIENT_GET_CLASS (client);
 	g_return_val_if_fail (klass != NULL, FALSE);
 	g_return_val_if_fail (klass->open_sync != NULL, FALSE);
 
-	res = klass->open_sync (client, only_if_exists, cancellable, error);
-
-	client->priv->opened = res;
-
-	return res;
+	return klass->open_sync (client, only_if_exists, cancellable, error);
 }
 
 /**
@@ -1663,6 +1700,8 @@ e_client_util_unwrap_dbus_error (GError *dbus_error, GError **client_error, cons
 					return TRUE;
 				}
 			}
+
+			g_free (name);
 		}
 	}
 
diff --git a/libedataserver/e-client.h b/libedataserver/e-client.h
index b2ece72..5db9afb 100644
--- a/libedataserver/e-client.h
+++ b/libedataserver/e-client.h
@@ -36,7 +36,8 @@
 #define E_IS_CLIENT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CLIENT))
 #define E_CLIENT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CLIENT, EClientClass))
 
-#define CLIENT_BACKEND_PROPERTY_LOADED			"loaded"
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
 #define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
 #define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
 #define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
@@ -103,6 +104,7 @@ struct _EClientClass {
 
 	/* signals */
 	gboolean	(* authenticate) (EClient *client, ECredentials *credentials);
+	void		(* opened) (EClient *client, const GError *error);
 	void		(* backend_error) (EClient *client, const gchar *error_msg);
 	void		(* backend_died) (EClient *client);
 };
diff --git a/libedataserver/e-credentials.h b/libedataserver/e-credentials.h
index 223e344..06b0f26 100644
--- a/libedataserver/e-credentials.h
+++ b/libedataserver/e-credentials.h
@@ -39,6 +39,7 @@ typedef struct _ECredentials
 #define E_CREDENTIALS_KEY_AUTH_DOMAIN	"auth-domain"
 #define E_CREDENTIALS_KEY_PROMPT_TITLE	"prompt-title"
 #define E_CREDENTIALS_KEY_PROMPT_TEXT	"prompt-text"
+#define E_CREDENTIALS_KEY_PROMPT_REASON	"prompt-reason"
 #define E_CREDENTIALS_KEY_PROMPT_KEY	"prompt-key"
 #define E_CREDENTIALS_KEY_PROMPT_FLAGS	"prompt-flags"
 
diff --git a/libedataserver/e-gdbus-templates.c b/libedataserver/e-gdbus-templates.c
index bf0f01c..3d8b450 100644
--- a/libedataserver/e-gdbus-templates.c
+++ b/libedataserver/e-gdbus-templates.c
@@ -1661,3 +1661,50 @@ e_gdbus_proxy_method_call_sync_strv__string (const gchar *method_name, GDBusProx
 {
 	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRING, out_string, proxy, cancellable, error);
 }
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_templates_encode_error (const GError *in_error)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+
+	if (!in_error) {
+		strv[0] = g_strdup ("");
+		strv[1] = g_strdup ("");
+	} else {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
+
+		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
+		strv[1] = e_util_utf8_make_valid (in_error->message);
+
+		g_free (dbus_error_name);
+	}
+
+	return strv;
+}
+
+/* free *out_error with g_error_free(), if not NULL */
+gboolean
+e_gdbus_templates_decode_error (const gchar * const *in_strv, GError **out_error)
+{
+	const gchar *error_name, *error_message;
+
+	g_return_val_if_fail (out_error != NULL, FALSE);
+
+	*out_error = NULL;
+
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+
+	error_name = in_strv[0];
+	error_message = in_strv[1];
+
+	if (error_name && *error_name && error_message)
+		*out_error = g_dbus_error_new_for_dbus_error (error_name, error_message);
+
+	return TRUE;
+}
diff --git a/libedataserver/e-gdbus-templates.h b/libedataserver/e-gdbus-templates.h
index bedb51e..ce32798 100644
--- a/libedataserver/e-gdbus-templates.h
+++ b/libedataserver/e-gdbus-templates.h
@@ -163,17 +163,17 @@ enum {
 		(GDBusAnnotationInfo **) NULL,								\
 	};
 
-#define E_DECLARE_GDBUS_SYNC_METHOD_0(_where, _name)							\
-	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _name =				\
+#define E_DECLARE_GDBUS_SYNC_METHOD_0(_where, _mname)							\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
 	{												\
 		-1,											\
-		(gchar *) # _name,									\
+		(gchar *) # _mname,									\
 		(GDBusArgInfo **) NULL,									\
 		(GDBusArgInfo **) NULL,									\
 		(GDBusAnnotationInfo **) NULL,								\
 	};
 
-#define E_DECLARE_GDBUS_SYNC_METHOD_1(_where, _name, _p1_name, _p1_type)				\
+#define E_DECLARE_GDBUS_SYNC_METHOD_1(_where, _mname, _p1_name, _p1_type)				\
 	E_DECLARE_GDBUS_ARG (_where, _mname, method_in, _p1_name, _p1_type)				\
 													\
 	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname[] =	\
@@ -182,10 +182,10 @@ enum {
 		NULL											\
 	};												\
 													\
-	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _name =				\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
 	{												\
 		-1,											\
-		(gchar *) # _name,									\
+		(gchar *) # _mname,									\
 		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname,		\
 		(GDBusArgInfo **) NULL,									\
 		(GDBusAnnotationInfo **) NULL,								\
@@ -742,6 +742,9 @@ gboolean e_gdbus_proxy_method_call_sync_uint__void	(const gchar *method_name, GD
 gboolean e_gdbus_proxy_method_call_sync_string__string	(const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error);
 gboolean e_gdbus_proxy_method_call_sync_strv__string	(const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error);
 
+gchar ** e_gdbus_templates_encode_error	(const GError *in_error);
+gboolean e_gdbus_templates_decode_error	(const gchar * const *in_strv, GError **out_error);
+
 G_END_DECLS
 
 #endif /* E_GDBUS_TEMPLATES_H */
diff --git a/libedataserverui/e-client-utils.c b/libedataserverui/e-client-utils.c
index d7ad96a..032ee5e 100644
--- a/libedataserverui/e-client-utils.c
+++ b/libedataserverui/e-client-utils.c
@@ -264,6 +264,357 @@ e_client_utils_get_sources (ESourceList **sources, EClientSourceType source_type
 	return res;
 }
 
+typedef struct _EClientUtilsAsyncOpData
+{
+	EClientUtilsAuthenticateHandler auth_handler;
+	gpointer auth_handler_user_data;
+	GAsyncReadyCallback async_cb;
+	gpointer async_cb_user_data;
+	GCancellable *cancellable;
+	EClient *client;
+	ECredentials *used_credentials;
+	gboolean open_finished;
+	GError *opened_cb_error;
+} EClientUtilsAsyncOpData;
+
+static void
+free_client_utils_async_op_data (EClientUtilsAsyncOpData *async_data)
+{
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->cancellable != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	g_signal_handlers_disconnect_matched (async_data->cancellable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
+	g_signal_handlers_disconnect_matched (async_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
+
+	if (async_data->used_credentials)
+		e_credentials_free (async_data->used_credentials);
+	if (async_data->opened_cb_error)
+		g_error_free (async_data->opened_cb_error);
+	g_object_unref (async_data->cancellable);
+	g_object_unref (async_data->client);
+	g_free (async_data);
+}
+
+static gboolean
+complete_async_op_in_idle_cb (gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	gint run_main_depth;
+
+	g_return_val_if_fail (simple != NULL, FALSE);
+
+	run_main_depth = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "run-main-depth"));
+	if (run_main_depth < 1)
+		run_main_depth = 1;
+
+	/* do not receive in higher level than was initially run */
+	if (g_main_depth () > run_main_depth) {
+		return TRUE;
+	}
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+
+	return FALSE;
+}
+
+#define return_async_error_if_fail(expr, async_cb, async_cb_user_data, source_tag) G_STMT_START {	\
+	if (G_LIKELY ((expr))) { } else {								\
+		GError *error;										\
+													\
+		error = g_error_new (E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG,			\
+				"%s: assertion '%s' failed", G_STRFUNC, #expr);				\
+													\
+		return_async_error (error, async_cb, async_cb_user_data, source_tag);			\
+		g_error_free (error);									\
+		return;											\
+	}												\
+	} G_STMT_END
+
+static void
+return_async_error (const GError *error, GAsyncReadyCallback async_cb, gpointer async_cb_user_data, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (error != NULL);
+	g_return_if_fail (source_tag != NULL);
+
+	simple = g_simple_async_result_new (NULL, async_cb, async_cb_user_data, source_tag);
+	g_simple_async_result_set_from_error (simple, error);
+
+	g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
+	g_idle_add (complete_async_op_in_idle_cb, simple);
+}
+
+static void
+client_utils_open_new_done (EClientUtilsAsyncOpData *async_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	/* keep the initial auth_handler connected directly, thus it will be able
+	   to answer any later authentication requests, for reconnection, for example
+	*/
+	if (async_data->auth_handler)
+		g_signal_connect (async_data->client, "authenticate", G_CALLBACK (async_data->auth_handler), async_data->auth_handler_user_data);
+
+	simple = g_simple_async_result_new (NULL, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+	g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (async_data->client), g_object_unref);
+
+	g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
+	g_idle_add (complete_async_op_in_idle_cb, simple);
+
+	free_client_utils_async_op_data (async_data);
+}
+
+static void
+client_utils_open_new_cancelled_cb (GCancellable *cancellable, EClientUtilsAsyncOpData *async_data)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (cancellable != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->cancellable == cancellable);
+	g_return_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
+
+	return_async_error (error, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+	free_client_utils_async_op_data (async_data);
+	g_error_free (error);
+}
+
+static void
+finish_or_retry_open (EClientUtilsAsyncOpData *async_data, const GError *error)
+{
+	g_return_if_fail (async_data != NULL);
+
+	if (async_data->auth_handler && error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
+		if (async_data->used_credentials) {
+			const gchar *auth_domain, *prompt_key;
+
+			auth_domain = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN);
+			prompt_key = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
+
+			/* make sure the old password is forgotten when authentication failed */
+			if (auth_domain && prompt_key)
+				e_passwords_forget_password (auth_domain, prompt_key);
+
+			e_credentials_set (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON, error->message);
+		}
+
+		e_client_process_authentication (async_data->client, async_data->used_credentials);
+	} else if (error) {
+		return_async_error (error, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+		free_client_utils_async_op_data (async_data);
+	} else {
+		client_utils_open_new_done (async_data);
+	}
+}
+
+static void
+client_utils_opened_cb (EClient *client, const GError *error, EClientUtilsAsyncOpData *async_data)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (client == async_data->client);
+
+	if (!async_data->open_finished) {
+		/* there can happen that the "opened" signal is received
+		   before the e_client_open() is finished, thus keep detailed
+		   error for later use, if any */
+		if (error)
+			async_data->opened_cb_error = g_error_copy (error);
+	} else {
+		finish_or_retry_open (async_data, error);
+	}
+}
+
+static void
+client_utils_open_new_async_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EClientUtilsAsyncOpData *async_data = user_data;
+	GError *error = NULL;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (result != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->async_cb != NULL);
+	g_return_if_fail (async_data->client == E_CLIENT (source_object));
+
+	async_data->open_finished = TRUE;
+
+	if (!e_client_open_finish (E_CLIENT (source_object), result, &error)
+	    || g_cancellable_set_error_if_cancelled (async_data->cancellable, &error)) {
+		finish_or_retry_open (async_data, error);
+		g_error_free (error);
+		return;
+	}
+
+	if (async_data->opened_cb_error) {
+		finish_or_retry_open (async_data, async_data->opened_cb_error);
+		return;
+	}
+
+	if (e_client_is_opened (async_data->client)) {
+		client_utils_open_new_done (async_data);
+		return;
+	}
+
+	/* wait for 'opened' signal, which is received in client_utils_opened_cb */
+	g_signal_connect (async_data->cancellable, "cancelled", G_CALLBACK (client_utils_open_new_cancelled_cb), async_data);
+}
+
+static gboolean
+client_utils_open_new_auth_cb (EClient *client, ECredentials *credentials, gpointer user_data)
+{
+	EClientUtilsAsyncOpData *async_data = user_data;
+	gboolean handled;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->auth_handler != NULL, FALSE);
+
+	if (async_data->used_credentials) {
+		const gchar *reason = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
+
+		if (reason) {
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, NULL);
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_REASON, reason);
+		}
+	}
+
+	handled = async_data->auth_handler (client, credentials, async_data->auth_handler_user_data);
+
+	if (handled && credentials) {
+		if (async_data->used_credentials) {
+			gchar *prompt_flags_str;
+			guint prompt_flags = 0;
+
+			e_credentials_free (async_data->used_credentials);
+
+			prompt_flags_str = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS);
+			if (prompt_flags_str) {
+				prompt_flags = e_credentials_util_string_to_prompt_flags (prompt_flags_str);
+				g_free (prompt_flags_str);
+			} else {
+				prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
+					     | E_CREDENTIALS_PROMPT_FLAG_SECRET
+					     | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
+			}
+
+			prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
+
+			prompt_flags_str = e_credentials_util_prompt_flags_to_string (prompt_flags);
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS, prompt_flags_str);
+			g_free (prompt_flags_str);
+		}
+
+		async_data->used_credentials = e_credentials_new_clone (credentials);
+	}
+
+	return handled;
+}
+
+/**
+ * e_client_utils_open_new:
+ * @source: an #ESource to be opened
+ * @source_type: an #EClientSourceType of the @source
+ * @only_if_exists: if %TRUE, fail if this client doesn't already exist, otherwise create it first
+ * @auth_handler: authentication handler, to be used; the e_client_utils_authenticate_handler() is usually sufficient
+ * @auth_handler_user_data: user data for @auth_handler function
+ * @cancellable: a #GCancellable; can be %NULL
+ * @async_cb: callback to call when a result is ready
+ * @async_cb_user_data: user data for the @async_cb
+ *
+ * Begins asynchronous opening of a new #EClient corresponding
+ * to the @source of type @source_type. The resulting #EClient
+ * is fully opened and authenticated client, ready to be used.
+ * This call is finished by e_client_utils_open_new_finish()
+ * from the @async_cb.
+ *
+ * Note: the @auth_handler, and its @auth_handler_user_data,
+ * should be valid through whole live of returned #EClient.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_utils_open_new (ESource *source, EClientSourceType source_type, gboolean only_if_exists,
+			 EClientUtilsAuthenticateHandler auth_handler, gpointer auth_handler_user_data,
+			 GCancellable *cancellable, GAsyncReadyCallback async_cb, gpointer async_cb_user_data)
+{
+	EClient *client;
+	GError *error = NULL;
+	EClientUtilsAsyncOpData *async_data;
+
+	g_return_if_fail (async_cb != NULL);
+	return_async_error_if_fail (source != NULL, async_cb, async_cb_user_data, e_client_utils_open_new);
+	return_async_error_if_fail (E_IS_SOURCE (source), async_cb, async_cb_user_data, e_client_utils_open_new);
+
+	client = e_client_utils_new (source, source_type, &error);
+	if (!client) {
+		return_async_error (error, async_cb, async_cb_user_data, e_client_utils_open_new);
+		g_error_free (error);
+		return;
+	}
+
+	async_data = g_new0 (EClientUtilsAsyncOpData, 1);
+	async_data->auth_handler = auth_handler;
+	async_data->auth_handler_user_data = auth_handler_user_data;
+	async_data->async_cb = async_cb;
+	async_data->async_cb_user_data = async_cb_user_data;
+	async_data->client = client;
+	async_data->open_finished = FALSE;
+	if (cancellable)
+		async_data->cancellable = g_object_ref (cancellable);
+	else
+		async_data->cancellable = g_cancellable_new ();
+
+	if (auth_handler)
+		g_signal_connect (client, "authenticate", G_CALLBACK (client_utils_open_new_auth_cb), async_data);
+
+
+	/* wait till backend notifies about its opened state */
+	g_signal_connect (client, "opened", G_CALLBACK (client_utils_opened_cb), async_data);
+
+	e_client_open (client, only_if_exists, async_data->cancellable, client_utils_open_new_async_cb, async_data);
+}
+
+/**
+ * e_client_utils_open_new_finish:
+ * @result: a #GAsyncResult
+ * @client: (out): Return value for an #EClient.
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_utils_open_new() and
+ * sets @client to a fully opened and authenticated #EClient.
+ * This @client, if not NULL, should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_utils_open_new_finish (GAsyncResult *result, EClient **client, GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, e_client_utils_open_new), FALSE);
+
+	*client = NULL;
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	*client = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+
+	return *client != NULL;
+}
+
 /* This function is suitable as a handler for EClient::authenticate signal.
    It takes care of all the password prompt and such and returns TRUE if
    credentials (password) were provided. Thus just connect it to that signal
@@ -298,18 +649,24 @@ e_client_utils_authenticate_handler (EClient *client, ECredentials *credentials,
 		e_credentials_set (credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN, is_book ? E_CREDENTIALS_AUTH_DOMAIN_ADDRESSBOOK : E_CREDENTIALS_AUTH_DOMAIN_CALENDAR);
 
 	if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT)) {
-		gchar *prompt;
+		gchar *prompt, *reason;
 		gchar *username_markup, *source_name_markup;
 
+		reason = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
 		username_markup = g_markup_printf_escaped ("<b>%s</b>", e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME));
 		source_name_markup = g_markup_printf_escaped ("<b>%s</b>", e_source_peek_name (source));
 
-		prompt = g_strdup_printf (_("Enter password for %s (user %s)"), source_name_markup, username_markup);
+
+		if (reason && *reason)
+			prompt = g_strdup_printf (_("Enter password for %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
+		else
+			prompt = g_strdup_printf (_("Enter password for %s (user %s)"), source_name_markup, username_markup);
 
 		e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, prompt);
 
 		g_free (username_markup);
 		g_free (source_name_markup);
+		g_free (reason);
 		g_free (prompt);
 	}
 
@@ -373,7 +730,9 @@ e_credentials_authenticate_helper (ECredentials *credentials, GtkWindow *parent,
 	if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS)) {
 		prompt_flags = e_credentials_util_string_to_prompt_flags (e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS));
 	} else {
-		prompt_flags = E_CREDENTIALS_PROMPT_FLAG_SECRET | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
+		prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
+			     | E_CREDENTIALS_PROMPT_FLAG_SECRET
+			     | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
 	}
 
 	if (!remember_password) {
diff --git a/libedataserverui/e-client-utils.h b/libedataserverui/e-client-utils.h
index b97c9c0..b6a189f 100644
--- a/libedataserverui/e-client-utils.h
+++ b/libedataserverui/e-client-utils.h
@@ -33,7 +33,8 @@ typedef enum {
 	E_CLIENT_SOURCE_TYPE_CONTACTS,
 	E_CLIENT_SOURCE_TYPE_EVENTS,
 	E_CLIENT_SOURCE_TYPE_MEMOS,
-	E_CLIENT_SOURCE_TYPE_TASKS
+	E_CLIENT_SOURCE_TYPE_TASKS,
+	E_CLIENT_SOURCE_TYPE_LAST
 } EClientSourceType;
 
 typedef gboolean (* EClientUtilsAuthenticateHandler) (EClient *client, ECredentials *credentials, gpointer user_data);
@@ -47,6 +48,11 @@ gboolean	e_client_utils_set_default		(EClient *client, EClientSourceType source_
 gboolean	e_client_utils_set_default_source	(ESource *source, EClientSourceType source_type, GError **error);
 gboolean	e_client_utils_get_sources		(ESourceList **sources, EClientSourceType source_type, GError **error);
 
+void		e_client_utils_open_new			(ESource *source, EClientSourceType source_type, gboolean only_if_exists,
+							 EClientUtilsAuthenticateHandler auth_handler, gpointer auth_handler_user_data,
+							 GCancellable *cancellable, GAsyncReadyCallback async_cb, gpointer async_cb_user_data);
+gboolean	e_client_utils_open_new_finish		(GAsyncResult *result, EClient **client, GError **error);
+
 gboolean	e_client_utils_authenticate_handler	(EClient *client, ECredentials *credentials, gpointer unused_user_data);
 gboolean	e_credentials_authenticate_helper	(ECredentials *credentials, GtkWindow *parent, gboolean *remember_password);
 
diff --git a/tests/libebook/client/client-test-utils.c b/tests/libebook/client/client-test-utils.c
index 6a7004e..13acd6a 100644
--- a/tests/libebook/client/client-test-utils.c
+++ b/tests/libebook/client/client-test-utils.c
@@ -294,9 +294,8 @@ foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **so
 
 	do {
 		async_data->current_group = async_data->current_group->next;
-		if (async_data->current_group) {
+		if (async_data->current_group)
 			async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
-		}
 	} while (async_data->current_group && !async_data->current_source);
 
 	if (async_data->current_source) {
diff --git a/tests/libebook/client/test-client-examine.c b/tests/libebook/client/test-client-examine.c
index 731eb9f..687c74a 100644
--- a/tests/libebook/client/test-client-examine.c
+++ b/tests/libebook/client/test-client-examine.c
@@ -14,7 +14,8 @@ get_known_prop_names (void)
 {
 	GSList *prop_names = NULL;
 
-	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_LOADED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
@@ -87,6 +88,7 @@ print_values (const ExtraValues *evals, EClient *client)
 
 	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
 	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
 	g_print ("\tcapabilities: ");
 	values = e_client_get_capabilities (client);
 	if (!values) {
@@ -360,8 +362,6 @@ in_main_thread_idle_cb (gpointer unused)
 {
 	g_print ("* run in main thread with mainloop running\n");
 	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
 	g_print ("---------------------------------------------------------\n\n");
 
 	g_print ("* run in main thread async\n");
@@ -377,8 +377,6 @@ worker_thread (gpointer unused)
 {
 	g_print ("* run in dedicated thread with mainloop running\n");
 	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
 	g_print ("---------------------------------------------------------\n\n");
 
 	g_idle_add (in_main_thread_idle_cb, NULL);
@@ -393,8 +391,6 @@ main (gint argc, gchar **argv)
 
 	g_print ("* run in main thread without mainloop\n");
 	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
-	foreach_configured_source (check_source_sync);
 	g_print ("---------------------------------------------------------\n\n");
 
 	start_in_thread_with_main_loop (worker_thread, NULL);
diff --git a/tests/libecal/client/test-client-examine.c b/tests/libecal/client/test-client-examine.c
index 0d994be..3a1298e 100644
--- a/tests/libecal/client/test-client-examine.c
+++ b/tests/libecal/client/test-client-examine.c
@@ -14,7 +14,8 @@ get_known_prop_names (void)
 {
 	GSList *prop_names = NULL;
 
-	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_LOADED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
 	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
@@ -108,6 +109,7 @@ print_values (const ExtraValues *evals, EClient *client)
 
 	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
 	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
 	g_print ("\tcache dir: %s%s%s\n", evals->cache_dir ? "'" : "", evals->cache_dir ? evals->cache_dir : "none", evals->cache_dir ? "'" : "");
 	g_print ("\tcapabilities: ");
 	values = e_client_get_capabilities (client);
diff --git a/tests/libedataserverui/Makefile.am b/tests/libedataserverui/Makefile.am
index 4473a07..4603dff 100644
--- a/tests/libedataserverui/Makefile.am
+++ b/tests/libedataserverui/Makefile.am
@@ -1,5 +1,6 @@
 noinst_PROGRAMS = 							\
 	test-category-completion					\
+	test-client-examine-auth					\
 	test-source-combo-box						\
 	test-source-selector						\
 	test-contact-store						\
@@ -27,6 +28,10 @@ test_category_completion_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
 test_category_completion_SOURCES = test-category-completion.c
 test_category_completion_LDADD = $(TEST_EDATASERVERUI_LDFLAGS)
 
+test_client_examine_auth_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
+test_client_examine_auth_SOURCES = test-client-examine-auth.c
+test_client_examine_auth_LDADD = $(TEST_EDATASERVERUI_LDFLAGS)
+
 test_source_selector_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
 test_source_selector_SOURCES = test-source-selector.c
 test_source_selector_LDADD =  $(TEST_EDATASERVERUI_LDFLAGS)
diff --git a/tests/libedataserverui/test-client-examine-auth.c b/tests/libedataserverui/test-client-examine-auth.c
new file mode 100644
index 0000000..d63f4d5
--- /dev/null
+++ b/tests/libedataserverui/test-client-examine-auth.c
@@ -0,0 +1,418 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <glib.h>
+
+#include <libedataserver/e-source-group.h>
+#include <libedataserverui/e-client-utils.h>
+#include <libedataserverui/e-passwords.h>
+
+static void stop_main_loop (gint stop_result);
+static void report_error (const gchar *operation, GError **error);
+static gpointer foreach_configured_source_async_start (ESource **source);
+static gboolean foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source);
+static gboolean foreach_async (void);
+
+static gint running_async = 0;
+static EClientSourceType source_type = E_CLIENT_SOURCE_TYPE_CONTACTS;
+
+static GSList *
+get_known_prop_names (void)
+{
+	GSList *prop_names = NULL;
+
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CAPABILITIES);
+
+	return prop_names;
+}
+
+typedef struct _ExtraValues {
+	gpointer async_data;
+
+	GSList *todo_prop_names;
+	GHashTable *retrieved_props;
+} ExtraValues;
+
+static void
+extra_values_free (ExtraValues *evals)
+{
+	if (!evals)
+		return;
+
+	g_slist_free (evals->todo_prop_names);
+	g_hash_table_destroy (evals->retrieved_props);
+	g_free (evals);
+}
+
+static void
+print_each_property (gpointer prop_name, gpointer prop_value, gpointer user_data)
+{
+	g_return_if_fail (prop_name != NULL);
+
+	if (prop_value == NULL) {
+		g_print ("\t   %s: NULL\n", (const gchar *) prop_name);
+		return;
+	}
+
+	g_print ("\t   %s: ", (const gchar *) prop_name);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		GSList *values = e_client_util_parse_comma_strings (prop_value), *v;
+
+		
+		for (v = values; v; v = v->next) {
+			if (v != values)
+				g_print (", ");
+
+			g_print ("'%s'", (const gchar *) v->data);
+		}
+
+		e_client_util_free_string_slist (values);
+	} else {
+		g_print ("'%s'", (const gchar *) prop_value);
+	}
+
+	g_print ("\n");
+}
+
+static void
+print_values (const ExtraValues *evals, EClient *client)
+{
+	const GSList *values;
+
+	g_return_if_fail (evals != NULL);
+
+	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
+	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
+	g_print ("\tcapabilities: ");
+	values = e_client_get_capabilities (client);
+	if (!values) {
+		g_print ("NULL");
+	} else {
+		while (values) {
+			const gchar *cap = values->data;
+
+			g_print ("'%s'", cap);
+			if (!e_client_check_capability (client, cap))
+				g_print (" (not found in EClient)");
+
+			values = values->next;
+
+			if (values)
+				g_print (", ");
+		}
+	}
+	g_print ("\n");
+
+	g_print ("\tbackend properties:\n");
+	g_hash_table_foreach (evals->retrieved_props, print_each_property, NULL);
+}
+
+static void
+identify_source (ESource *source)
+{
+	const gchar *name, *uri;
+	gchar *abs_uri = NULL;
+
+	g_return_if_fail (source != NULL);
+
+	name = e_source_peek_name (source);
+	if (!name)
+		name = "Unknown name";
+
+	uri = e_source_peek_absolute_uri (source);
+	if (!uri) {
+		abs_uri = e_source_build_absolute_uri (source);
+		uri = abs_uri;
+	}
+	if (!uri)
+		uri = e_source_peek_relative_uri (source);
+	if (!uri)
+		uri = "Unknown uri";
+
+	g_print ("\n   Checking source '%s' (%s)\n", name, uri);
+
+	g_free (abs_uri);
+}
+
+static void client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data);
+
+static void
+continue_next_source (gpointer async_data)
+{
+	ESource *source = NULL;
+
+	g_return_if_fail (async_data != NULL);
+
+	while (async_data && foreach_configured_source_async_next (&async_data, &source)) {
+		identify_source (source);
+		e_client_utils_open_new (source, source_type, TRUE,
+			e_client_utils_authenticate_handler, NULL,
+			NULL, client_opened_async, async_data);
+		break;
+	}
+
+	if (!async_data) {
+		running_async--;
+		if (!running_async) {
+			while (source_type++, source_type < E_CLIENT_SOURCE_TYPE_LAST) {
+				if (foreach_async ())
+					return;
+			}
+
+			stop_main_loop (0);
+		}
+	}
+}
+
+static void
+client_got_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	gchar *prop_value = NULL;
+	GError *error = NULL;
+	EClient *client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	client = E_CLIENT (source_object);
+
+	if (!e_client_get_backend_property_finish (client, result, &prop_value, &error)) {
+		report_error ("get backend property finish", &error);
+	}
+
+	g_hash_table_insert (evals->retrieved_props, evals->todo_prop_names->data, prop_value);
+	evals->todo_prop_names = g_slist_remove (evals->todo_prop_names, evals->todo_prop_names->data);
+
+	if (!evals->todo_prop_names) {
+		/* to cache them, as it can be fetched with idle as well */
+		e_client_get_capabilities (client);
+
+		print_values (evals, client);
+
+		g_object_unref (source_object);
+
+		continue_next_source (evals->async_data);
+		extra_values_free (evals);
+	} else {
+		e_client_get_backend_property (client, evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+	}
+}
+
+static void
+client_set_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	GError *error = NULL;
+	EClient *client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	client = E_CLIENT (source_object);
+
+	if (!e_client_set_backend_property_finish (client, result, &error)) {
+		/* it may fail on the set_backend_property */
+		g_clear_error (&error);
+	} else {
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	e_client_get_backend_property (client, evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+}
+
+static void
+client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data)
+{
+	ExtraValues *evals;
+	GError *error = NULL;
+	EClient *client = NULL;
+
+	g_return_if_fail (source_object == NULL);
+	g_return_if_fail (async_data != NULL);
+
+	if (!e_client_utils_open_new_finish (result, &client, &error)) {
+		report_error ("client utils open new finish", &error);
+		continue_next_source (async_data);
+		return;
+	}
+
+	evals = g_new0 (ExtraValues, 1);
+	evals->async_data = async_data;
+	evals->todo_prop_names = get_known_prop_names ();
+	evals->retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	e_client_set_backend_property (client, "*unknown*property*", "*value*", NULL, client_set_backend_property_async, evals);
+}
+
+static gboolean
+foreach_async (void)
+{
+	gpointer async_data;
+	ESource *source = NULL;
+
+	async_data = foreach_configured_source_async_start (&source);
+	if (!async_data) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	running_async++;
+
+	identify_source (source);
+	e_client_utils_open_new (source, source_type, TRUE,
+		e_client_utils_authenticate_handler, NULL,
+		NULL, client_opened_async, async_data);
+
+	return TRUE;
+}
+
+static gboolean
+in_main_thread_idle_cb (gpointer unused)
+{
+	if (!foreach_async ())
+		return FALSE;
+
+	return FALSE;
+}
+
+static GMainLoop *loop = NULL;
+static gint main_stop_result = 0;
+
+static void
+stop_main_loop (gint stop_result)
+{
+	g_return_if_fail (loop != NULL);
+
+	main_stop_result = stop_result;
+	g_main_loop_quit (loop);
+}
+
+static gint
+get_main_loop_stop_result (void)
+{
+	return main_stop_result;
+}
+
+struct ForeachConfiguredData
+{
+	ESourceList *source_list;
+	GSList *current_group;
+	GSList *current_source;
+};
+
+static gpointer
+foreach_configured_source_async_start (ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+	ESourceList *source_list = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	if (!e_client_utils_get_sources (&source_list, source_type, &error)) {
+		report_error ("get sources", &error);
+		return NULL;
+	}
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+
+	async_data = g_new0 (struct ForeachConfiguredData, 1);
+	async_data->source_list = source_list;
+	async_data->current_group = e_source_list_peek_groups (source_list);
+	if (!async_data->current_group) {
+		gpointer ad = async_data;
+
+		foreach_configured_source_async_next (&ad, source);
+		return ad;
+	}
+
+	async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	if (!async_data->current_source) {
+		gpointer ad = async_data;
+
+		if (foreach_configured_source_async_next (&ad, source))
+			return ad;
+
+		return NULL;
+	}
+
+	*source = async_data->current_source->data;
+
+	return async_data;
+}
+
+static gboolean
+foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+
+	g_return_val_if_fail (foreach_async_data != NULL, FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	async_data = *foreach_async_data;
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->source_list != NULL, FALSE);
+	g_return_val_if_fail (async_data->current_group != NULL, FALSE);
+
+	if (async_data->current_source)
+		async_data->current_source = async_data->current_source->next;
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	do {
+		async_data->current_group = async_data->current_group->next;
+		if (async_data->current_group)
+			async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	} while (async_data->current_group && !async_data->current_source);
+
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	g_object_unref (async_data->source_list);
+	g_free (async_data);
+
+	*foreach_async_data = NULL;
+
+	return FALSE;
+}
+
+static void
+report_error (const gchar *operation, GError **error)
+{
+	g_return_if_fail (operation != NULL);
+
+	g_printerr ("Failed to %s: %s\n", operation, (error && *error) ? (*error)->message : "Unknown error");
+
+	g_clear_error (error);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	g_type_init ();
+	g_thread_init (NULL);
+	gtk_init (&argc, &argv);
+
+	e_passwords_init ();
+
+	g_idle_add (in_main_thread_idle_cb, NULL);
+
+	loop = g_main_loop_new (NULL, FALSE);
+	g_main_loop_run (loop);
+	g_main_loop_unref (loop);
+
+	return get_main_loop_stop_result ();
+}



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