[evolution-data-server] Bug 789169 - [CalDAV] Ask for credentials when PUT fails with Unauthorized
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 789169 - [CalDAV] Ask for credentials when PUT fails with Unauthorized
- Date: Tue, 24 Oct 2017 13:26:26 +0000 (UTC)
commit 252f5be5e2fb7ae235e99ec08d347e16beb19e7a
Author: Milan Crha <mcrha redhat com>
Date: Tue Oct 24 15:25:39 2017 +0200
Bug 789169 - [CalDAV] Ask for credentials when PUT fails with Unauthorized
.../backends/webdav/e-book-backend-webdav.c | 106 +++++---
.../libedata-book/e-book-meta-backend.c | 305 ++++++++++++++++++--
.../libedata-book/e-book-meta-backend.h | 11 +-
.../backends/caldav/e-cal-backend-caldav.c | 106 +++++---
src/calendar/libedata-cal/e-cal-meta-backend.c | 305 ++++++++++++++++++--
src/calendar/libedata-cal/e-cal-meta-backend.h | 10 +-
6 files changed, 719 insertions(+), 124 deletions(-)
---
diff --git a/src/addressbook/backends/webdav/e-book-backend-webdav.c
b/src/addressbook/backends/webdav/e-book-backend-webdav.c
index b3fe648..8a0c116 100644
--- a/src/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/src/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -543,6 +543,32 @@ ebb_webdav_search_changes_cb (EBookCache *book_cache,
return TRUE;
}
+static void
+ebb_webdav_check_credentials_error (EBookBackendWebDAV *bbdav,
+ GError *op_error)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND_WEBDAV (bbdav));
+
+ if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && bbdav->priv->webdav) {
+ op_error->domain = E_DATA_BOOK_ERROR;
+ op_error->code = E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE;
+ } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+ g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+ op_error->domain = E_DATA_BOOK_ERROR;
+ op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
+
+ if (bbdav->priv->webdav) {
+ ENamedParameters *credentials;
+
+ credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (bbdav->priv->webdav));
+ if (credentials && e_named_parameters_count (credentials) > 0)
+ op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED;
+
+ e_named_parameters_free (credentials);
+ }
+ }
+}
+
static gboolean
ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
const gchar *last_sync_tag,
@@ -645,42 +671,10 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
} while (success && link);
}
- if (local_error && !g_cancellable_is_cancelled (cancellable)) {
- ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
-
- if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
- reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
- g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
- reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
- }
-
- if (reason != E_SOURCE_CREDENTIALS_REASON_UNKNOWN) {
- GTlsCertificateFlags certificate_errors = 0;
- gchar *certificate_pem = NULL;
- GError *local_error2 = NULL;
-
- if (!e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav),
&certificate_pem, &certificate_errors)) {
- certificate_pem = NULL;
- certificate_errors = 0;
- }
-
- if (!e_backend_credentials_required_sync (E_BACKEND (bbdav), reason, certificate_pem,
certificate_errors,
- local_error, cancellable, &local_error2)) {
- g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC,
local_error2 ? local_error2->message : "Unknown error");
- } else {
- /* Ignore the error when the caller had been notified through the
credentials-required */
- g_clear_error (&local_error);
- success = TRUE;
- }
-
- g_clear_error (&local_error2);
- g_free (certificate_pem);
- }
- }
-
- if (local_error)
+ if (local_error) {
+ ebb_webdav_check_credentials_error (bbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
@@ -744,6 +738,7 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
{
EBookBackendWebDAV *bbdav;
EXmlDocument *xml;
+ GError *local_error = NULL;
gboolean success;
g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (meta_backend), FALSE);
@@ -771,13 +766,18 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
e_xml_document_end_element (xml); /* prop */
success = e_webdav_session_report_sync (bbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
- ebb_webdav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, error);
+ ebb_webdav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
g_object_unref (xml);
if (success)
*out_existing_objects = g_slist_reverse (*out_existing_objects);
+ if (local_error) {
+ ebb_webdav_check_credentials_error (bbdav, local_error);
+ g_propagate_error (error, local_error);
+ }
+
return success;
}
@@ -931,8 +931,10 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
g_free (etag);
g_free (bytes);
- if (local_error)
+ if (local_error) {
+ ebb_webdav_check_credentials_error (bbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
@@ -951,6 +953,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
EBookBackendWebDAV *bbdav;
gchar *href = NULL, *etag = NULL, *uid = NULL;
gchar *vcard_string = NULL;
+ GError *local_error = NULL;
gboolean success;
g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (meta_backend), FALSE);
@@ -988,7 +991,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
success = e_webdav_session_put_data_sync (bbdav->priv->webdav, (extra && *extra) ? extra :
href,
force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_VCARD,
- vcard_string, -1, out_new_extra, NULL, cancellable, error);
+ vcard_string, -1, out_new_extra, NULL, cancellable, &local_error);
/* To read the component back, because server can change it */
if (success)
@@ -1003,6 +1006,11 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
g_free (etag);
g_free (uid);
+ if (local_error) {
+ ebb_webdav_check_credentials_error (bbdav, local_error);
+ g_propagate_error (error, local_error);
+ }
+
return success;
}
@@ -1071,12 +1079,31 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
g_object_unref (contact);
g_free (etag);
- if (local_error)
+ if (local_error) {
+ ebb_webdav_check_credentials_error (bbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
+static gboolean
+ebb_webdav_get_ssl_error_details (EBookMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ EBookBackendWebDAV *bbdav;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (meta_backend), FALSE);
+
+ bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+
+ if (!bbdav->priv->webdav)
+ return FALSE;
+
+ return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+}
+
static gchar *
ebb_webdav_get_backend_property (EBookBackend *book_backend,
const gchar *prop_name)
@@ -1159,6 +1186,7 @@ e_book_backend_webdav_class_init (EBookBackendWebDAVClass *klass)
book_meta_backend_class->load_contact_sync = ebb_webdav_load_contact_sync;
book_meta_backend_class->save_contact_sync = ebb_webdav_save_contact_sync;
book_meta_backend_class->remove_contact_sync = ebb_webdav_remove_contact_sync;
+ book_meta_backend_class->get_ssl_error_details = ebb_webdav_get_ssl_error_details;
book_backend_class = E_BOOK_BACKEND_CLASS (klass);
book_backend_class->get_backend_property = ebb_webdav_get_backend_property;
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.c
b/src/addressbook/libedata-book/e-book-meta-backend.c
index 860a42a..0b296bf 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.c
+++ b/src/addressbook/libedata-book/e-book-meta-backend.c
@@ -52,9 +52,18 @@
#define LOCAL_PREFIX "file://"
+/* How many times can repeat an operation when credentials fail. */
+#define MAX_REPEAT_COUNT 3
+
+/* How long to wait for credentials, in seconds, during the operation repeat cycle */
+#define MAX_WAIT_FOR_CREDENTIALS_SECS 60
+
struct _EBookMetaBackendPrivate {
GMutex connect_lock;
GMutex property_lock;
+ GMutex wait_credentials_lock;
+ GCond wait_credentials_cond;
+ guint wait_credentials_stamp;
GError *create_cache_error;
EBookCache *cache;
ENamedParameters *last_credentials;
@@ -460,6 +469,14 @@ ebmb_requires_reconnect (EBookMetaBackend *meta_backend)
return requires;
}
+static gboolean
+ebmb_get_ssl_error_details (EBookMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ return FALSE;
+}
+
static GSList * /* gchar * */
ebmb_gather_photos_local_filenames (EBookMetaBackend *meta_backend,
EContact *contact)
@@ -2023,6 +2040,11 @@ ebmb_authenticate_sync (EBackend *backend,
g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE,
e_client_error_to_string (E_CLIENT_ERROR_REPOSITORY_OFFLINE));
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ meta_backend->priv->wait_credentials_stamp++;
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
return E_SOURCE_AUTHENTICATION_ERROR;
}
@@ -2030,6 +2052,9 @@ ebmb_authenticate_sync (EBackend *backend,
e_source_set_connection_status (e_backend_get_source (backend),
E_SOURCE_CONNECTION_STATUS_CONNECTING);
+ /* Always disconnect first, then provide new credentials. */
+ e_book_meta_backend_disconnect_sync (meta_backend, cancellable, NULL);
+
success = e_book_meta_backend_connect_sync (meta_backend, credentials, &auth_result,
out_certificate_pem, out_certificate_errors, cancellable, error);
@@ -2060,6 +2085,11 @@ ebmb_authenticate_sync (EBackend *backend,
g_mutex_unlock (&meta_backend->priv->property_lock);
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ meta_backend->priv->wait_credentials_stamp++;
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
if (refresh_after_authenticate)
e_book_meta_backend_schedule_refresh (meta_backend);
@@ -2164,6 +2194,87 @@ ebmb_cancel_view_cb (gpointer key,
}
static void
+ebmb_wait_for_credentials_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ EBookMetaBackend *meta_backend = user_data;
+
+ g_return_if_fail (E_IS_BOOK_META_BACKEND (meta_backend));
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+}
+
+static gboolean
+ebmb_maybe_wait_for_credentials (EBookMetaBackend *meta_backend,
+ guint wait_credentials_stamp,
+ const GError *op_error,
+ GCancellable *cancellable)
+{
+ EBackend *backend;
+ ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+ gchar *certificate_pem = NULL;
+ GTlsCertificateFlags certificate_errors = 0;
+ gboolean got_credentials = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
+
+ if (!op_error || g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ if (g_error_matches (op_error, E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE) &&
+ e_book_meta_backend_get_ssl_error_details (meta_backend, &certificate_pem, &certificate_errors)) {
+ reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+ } else if (g_error_matches (op_error, E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED))
{
+ reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+ } else if (g_error_matches (op_error, E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED)) {
+ reason = E_SOURCE_CREDENTIALS_REASON_REJECTED;
+ }
+
+ if (reason == E_SOURCE_CREDENTIALS_REASON_UNKNOWN)
+ return FALSE;
+
+ backend = E_BACKEND (meta_backend);
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+
+ if (wait_credentials_stamp != meta_backend->priv->wait_credentials_stamp ||
+ e_backend_credentials_required_sync (backend, reason, certificate_pem, certificate_errors,
+ op_error, cancellable, &local_error)) {
+ gint64 wait_end_time;
+ gulong handler_id;
+
+ wait_end_time = g_get_monotonic_time () + MAX_WAIT_FOR_CREDENTIALS_SECS * G_TIME_SPAN_SECOND;
+
+ handler_id = cancellable ? g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (ebmb_wait_for_credentials_cancelled_cb), meta_backend) : 0;
+
+ while (wait_credentials_stamp == meta_backend->priv->wait_credentials_stamp &&
+ !g_cancellable_is_cancelled (cancellable)) {
+ if (!g_cond_wait_until (&meta_backend->priv->wait_credentials_cond,
&meta_backend->priv->wait_credentials_lock, wait_end_time))
+ break;
+ }
+
+ if (handler_id)
+ g_signal_handler_disconnect (cancellable, handler_id);
+
+ if (wait_credentials_stamp != meta_backend->priv->wait_credentials_stamp)
+ got_credentials = e_source_get_connection_status (e_backend_get_source (backend)) ==
E_SOURCE_CONNECTION_STATUS_CONNECTED;
+ } else {
+ g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ }
+
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ g_free (certificate_pem);
+
+ return got_credentials;
+}
+
+static void
e_book_meta_backend_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -2311,6 +2422,8 @@ e_book_meta_backend_finalize (GObject *object)
g_mutex_clear (&meta_backend->priv->connect_lock);
g_mutex_clear (&meta_backend->priv->property_lock);
+ g_mutex_clear (&meta_backend->priv->wait_credentials_lock);
+ g_cond_clear (&meta_backend->priv->wait_credentials_cond);
g_hash_table_destroy (meta_backend->priv->view_cancellables);
/* Chain up to parent's method. */
@@ -2332,6 +2445,7 @@ e_book_meta_backend_class_init (EBookMetaBackendClass *klass)
klass->search_sync = ebmb_search_sync;
klass->search_uids_sync = ebmb_search_uids_sync;
klass->requires_reconnect = ebmb_requires_reconnect;
+ klass->get_ssl_error_details = ebmb_get_ssl_error_details;
book_backend_class = E_BOOK_BACKEND_CLASS (klass);
book_backend_class->get_backend_property = ebmb_get_backend_property;
@@ -2413,6 +2527,8 @@ e_book_meta_backend_init (EBookMetaBackend *meta_backend)
g_mutex_init (&meta_backend->priv->connect_lock);
g_mutex_init (&meta_backend->priv->property_lock);
+ g_mutex_init (&meta_backend->priv->wait_credentials_lock);
+ g_cond_init (&meta_backend->priv->wait_credentials_cond);
meta_backend->priv->view_cancellables = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
g_object_unref);
meta_backend->priv->current_online_state = FALSE;
@@ -3634,6 +3750,9 @@ e_book_meta_backend_get_changes_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
@@ -3647,16 +3766,35 @@ e_book_meta_backend_get_changes_sync (EBookMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->get_changes_sync != NULL, FALSE);
- return klass->get_changes_sync (meta_backend,
- last_sync_tag,
- is_repeat,
- out_new_sync_tag,
- out_repeat,
- out_created_objects,
- out_modified_objects,
- out_removed_objects,
- cancellable,
- error);
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->get_changes_sync (meta_backend,
+ last_sync_tag,
+ is_repeat,
+ out_new_sync_tag,
+ out_repeat,
+ out_created_objects,
+ out_modified_objects,
+ out_removed_objects,
+ cancellable,
+ &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ebmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -3693,6 +3831,9 @@ e_book_meta_backend_list_existing_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (out_existing_objects != NULL, FALSE);
@@ -3701,7 +3842,27 @@ e_book_meta_backend_list_existing_sync (EBookMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->list_existing_sync != NULL, FALSE);
- return klass->list_existing_sync (meta_backend, out_new_sync_tag, out_existing_objects, cancellable,
error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->list_existing_sync (meta_backend, out_new_sync_tag, out_existing_objects,
cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ebmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -3738,6 +3899,9 @@ e_book_meta_backend_load_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
@@ -3748,7 +3912,27 @@ e_book_meta_backend_load_contact_sync (EBookMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->load_contact_sync != NULL, FALSE);
- return klass->load_contact_sync (meta_backend, uid, extra, out_contact, out_extra, cancellable,
error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->load_contact_sync (meta_backend, uid, extra, out_contact, out_extra,
cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ebmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -3803,6 +3987,9 @@ e_book_meta_backend_save_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
@@ -3817,15 +4004,35 @@ e_book_meta_backend_save_contact_sync (EBookMetaBackend *meta_backend,
return FALSE;
}
- return klass->save_contact_sync (meta_backend,
- overwrite_existing,
- conflict_resolution,
- contact,
- extra,
- out_new_uid,
- out_new_extra,
- cancellable,
- error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->save_contact_sync (meta_backend,
+ overwrite_existing,
+ conflict_resolution,
+ contact,
+ extra,
+ out_new_uid,
+ out_new_extra,
+ cancellable,
+ &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ebmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -3858,6 +4065,9 @@ e_book_meta_backend_remove_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
@@ -3870,7 +4080,27 @@ e_book_meta_backend_remove_contact_sync (EBookMetaBackend *meta_backend,
return FALSE;
}
- return klass->remove_contact_sync (meta_backend, conflict_resolution, uid, extra, object,
cancellable, error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->remove_contact_sync (meta_backend, conflict_resolution, uid, extra, object,
cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ebmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -3991,3 +4221,34 @@ e_book_meta_backend_requires_reconnect (EBookMetaBackend *meta_backend)
return klass->requires_reconnect (meta_backend);
}
+
+/**
+ * e_book_meta_backend_get_ssl_error_details:
+ * @meta_backend: an #EBookMetaBackend
+ * @out_certificate_pem: (out): SSL certificate encoded in PEM format
+ * @out_certificate_errors: (out): bit-or of #GTlsCertificateFlags claiming the certificate errors
+ *
+ * It is optional to implement this virtual method by the descendants.
+ * It is used to receive SSL error details when any online operation
+ * returns E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE error.
+ *
+ * Returns: %TRUE, when the SSL error details had been available and
+ * the out parameters populated, %FALSE otherwise.
+ *
+ * Since: 3.28
+ **/
+gboolean
+e_book_meta_backend_get_ssl_error_details (EBookMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ EBookMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), FALSE);
+
+ klass = E_BOOK_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->get_ssl_error_details != NULL, FALSE);
+
+ return klass->get_ssl_error_details (meta_backend, out_certificate_pem, out_certificate_errors);
+}
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.h
b/src/addressbook/libedata-book/e-book-meta-backend.h
index 67adcb7..6389f9f 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.h
+++ b/src/addressbook/libedata-book/e-book-meta-backend.h
@@ -167,8 +167,13 @@ struct _EBookMetaBackendClass {
/* Signals */
void (* source_changed) (EBookMetaBackend *meta_backend);
+ gboolean (* get_ssl_error_details)
+ (EBookMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors);
+
/* Padding for future expansion */
- gpointer reserved[10];
+ gpointer reserved[9];
};
GType e_book_meta_backend_get_type (void) G_GNUC_CONST;
@@ -296,6 +301,10 @@ gboolean e_book_meta_backend_search_uids_sync
GError **error);
gboolean e_book_meta_backend_requires_reconnect
(EBookMetaBackend *meta_backend);
+gboolean e_book_meta_backend_get_ssl_error_details
+ (EBookMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors);
G_END_DECLS
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 577cf8b..75981d5 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -571,6 +571,32 @@ ecb_caldav_search_changes_cb (ECalCache *cal_cache,
return TRUE;
}
+static void
+ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
+ GError *op_error)
+{
+ g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav));
+
+ if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && cbdav->priv->webdav) {
+ op_error->domain = E_DATA_CAL_ERROR;
+ op_error->code = TLSNotAvailable;
+ } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+ g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+ op_error->domain = E_DATA_CAL_ERROR;
+ op_error->code = AuthenticationRequired;
+
+ if (cbdav->priv->webdav) {
+ ENamedParameters *credentials;
+
+ credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (cbdav->priv->webdav));
+ if (credentials && e_named_parameters_count (credentials) > 0)
+ op_error->code = AuthenticationFailed;
+
+ e_named_parameters_free (credentials);
+ }
+ }
+}
+
static gboolean
ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
const gchar *last_sync_tag,
@@ -728,42 +754,10 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
} while (success && link);
}
- if (local_error && !g_cancellable_is_cancelled (cancellable)) {
- ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
-
- if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
- reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
- g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
- reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
- }
-
- if (reason != E_SOURCE_CREDENTIALS_REASON_UNKNOWN) {
- GTlsCertificateFlags certificate_errors = 0;
- gchar *certificate_pem = NULL;
- GError *local_error2 = NULL;
-
- if (!e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav),
&certificate_pem, &certificate_errors)) {
- certificate_pem = NULL;
- certificate_errors = 0;
- }
-
- if (!e_backend_credentials_required_sync (E_BACKEND (cbdav), reason, certificate_pem,
certificate_errors,
- local_error, cancellable, &local_error2)) {
- g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC,
local_error2 ? local_error2->message : "Unknown error");
- } else {
- /* Ignore the error when the caller had been notified through the
credentials-required */
- g_clear_error (&local_error);
- success = TRUE;
- }
-
- g_clear_error (&local_error2);
- g_free (certificate_pem);
- }
- }
-
- if (local_error)
+ if (local_error) {
+ ecb_caldav_check_credentials_error (cbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
@@ -828,6 +822,7 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
ECalBackendCalDAV *cbdav;
icalcomponent_kind kind;
EXmlDocument *xml;
+ GError *local_error = NULL;
gboolean success;
g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (meta_backend), FALSE);
@@ -880,13 +875,18 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
e_xml_document_end_element (xml); /* filter */
success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
- ecb_caldav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, error);
+ ecb_caldav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
g_object_unref (xml);
if (success)
*out_existing_objects = g_slist_reverse (*out_existing_objects);
+ if (local_error) {
+ ecb_caldav_check_credentials_error (cbdav, local_error);
+ g_propagate_error (error, local_error);
+ }
+
return success;
}
@@ -1053,8 +1053,10 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
g_free (etag);
g_free (bytes);
- if (local_error)
+ if (local_error) {
+ ecb_caldav_check_credentials_error (cbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
@@ -1075,6 +1077,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
gchar *href = NULL, *etag = NULL, *uid = NULL;
gchar *ical_string = NULL;
gboolean success;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (meta_backend), FALSE);
g_return_val_if_fail (instances != NULL, FALSE);
@@ -1127,7 +1130,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
success = e_webdav_session_put_data_sync (cbdav->priv->webdav, (extra && *extra) ? extra :
href,
force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_CALENDAR,
- ical_string, -1, out_new_extra, NULL, cancellable, error);
+ ical_string, -1, out_new_extra, NULL, cancellable, &local_error);
/* To read the component back, because server can change it */
if (success)
@@ -1142,6 +1145,11 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
g_free (etag);
g_free (uid);
+ if (local_error) {
+ ecb_caldav_check_credentials_error (cbdav, local_error);
+ g_propagate_error (error, local_error);
+ }
+
return success;
}
@@ -1210,13 +1218,32 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
icalcomponent_free (icalcomp);
g_free (etag);
- if (local_error)
+ if (local_error) {
+ ecb_caldav_check_credentials_error (cbdav, local_error);
g_propagate_error (error, local_error);
+ }
return success;
}
static gboolean
+ecb_caldav_get_ssl_error_details (ECalMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ ECalBackendCalDAV *cbdav;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (meta_backend), FALSE);
+
+ cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+
+ if (!cbdav->priv->webdav)
+ return FALSE;
+
+ return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+}
+
+static gboolean
ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
xmlXPathContextPtr xpath_ctx,
const gchar *xpath_prop_prefix,
@@ -1881,6 +1908,7 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *klass)
cal_meta_backend_class->load_component_sync = ecb_caldav_load_component_sync;
cal_meta_backend_class->save_component_sync = ecb_caldav_save_component_sync;
cal_meta_backend_class->remove_component_sync = ecb_caldav_remove_component_sync;
+ cal_meta_backend_class->get_ssl_error_details = ecb_caldav_get_ssl_error_details;
cal_backend_sync_class = E_CAL_BACKEND_SYNC_CLASS (klass);
cal_backend_sync_class->get_free_busy_sync = ecb_caldav_get_free_busy_sync;
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index db6e5c2..8c9fc6c 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -49,9 +49,18 @@
#define LOCAL_PREFIX "file://"
+/* How many times can repeat an operation when credentials fail. */
+#define MAX_REPEAT_COUNT 3
+
+/* How long to wait for credentials, in seconds, during the operation repeat cycle */
+#define MAX_WAIT_FOR_CREDENTIALS_SECS 60
+
struct _ECalMetaBackendPrivate {
GMutex connect_lock;
GMutex property_lock;
+ GMutex wait_credentials_lock;
+ GCond wait_credentials_cond;
+ guint wait_credentials_stamp;
GError *create_cache_error;
ECalCache *cache;
ENamedParameters *last_credentials;
@@ -463,6 +472,14 @@ ecmb_requires_reconnect (ECalMetaBackend *meta_backend)
return requires;
}
+static gboolean
+ecmb_get_ssl_error_details (ECalMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ return FALSE;
+}
+
static void
ecmb_start_view_thread_func (ECalBackend *cal_backend,
gpointer user_data,
@@ -2792,6 +2809,11 @@ ecmb_authenticate_sync (EBackend *backend,
g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE,
e_client_error_to_string (E_CLIENT_ERROR_REPOSITORY_OFFLINE));
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ meta_backend->priv->wait_credentials_stamp++;
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
return E_SOURCE_AUTHENTICATION_ERROR;
}
@@ -2799,6 +2821,9 @@ ecmb_authenticate_sync (EBackend *backend,
e_source_set_connection_status (e_backend_get_source (backend),
E_SOURCE_CONNECTION_STATUS_CONNECTING);
+ /* Always disconnect first, then provide new credentials. */
+ e_cal_meta_backend_disconnect_sync (meta_backend, cancellable, NULL);
+
success = e_cal_meta_backend_connect_sync (meta_backend, credentials, &auth_result,
out_certificate_pem, out_certificate_errors, cancellable, error);
@@ -2829,6 +2854,11 @@ ecmb_authenticate_sync (EBackend *backend,
g_mutex_unlock (&meta_backend->priv->property_lock);
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ meta_backend->priv->wait_credentials_stamp++;
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
if (refresh_after_authenticate)
e_cal_meta_backend_schedule_refresh (meta_backend);
@@ -2933,6 +2963,87 @@ ecmb_cancel_view_cb (gpointer key,
}
static void
+ecmb_wait_for_credentials_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ ECalMetaBackend *meta_backend = user_data;
+
+ g_return_if_fail (E_IS_CAL_META_BACKEND (meta_backend));
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ g_cond_broadcast (&meta_backend->priv->wait_credentials_cond);
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+}
+
+static gboolean
+ecmb_maybe_wait_for_credentials (ECalMetaBackend *meta_backend,
+ guint wait_credentials_stamp,
+ const GError *op_error,
+ GCancellable *cancellable)
+{
+ EBackend *backend;
+ ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+ gchar *certificate_pem = NULL;
+ GTlsCertificateFlags certificate_errors = 0;
+ gboolean got_credentials = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+
+ if (!op_error || g_cancellable_is_cancelled (cancellable))
+ return FALSE;
+
+ if (g_error_matches (op_error, E_DATA_CAL_ERROR, TLSNotAvailable) &&
+ e_cal_meta_backend_get_ssl_error_details (meta_backend, &certificate_pem, &certificate_errors)) {
+ reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+ } else if (g_error_matches (op_error, E_DATA_CAL_ERROR, AuthenticationRequired)) {
+ reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+ } else if (g_error_matches (op_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
+ reason = E_SOURCE_CREDENTIALS_REASON_REJECTED;
+ }
+
+ if (reason == E_SOURCE_CREDENTIALS_REASON_UNKNOWN)
+ return FALSE;
+
+ backend = E_BACKEND (meta_backend);
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+
+ if (wait_credentials_stamp != meta_backend->priv->wait_credentials_stamp ||
+ e_backend_credentials_required_sync (backend, reason, certificate_pem, certificate_errors,
+ op_error, cancellable, &local_error)) {
+ gint64 wait_end_time;
+ gulong handler_id;
+
+ wait_end_time = g_get_monotonic_time () + MAX_WAIT_FOR_CREDENTIALS_SECS * G_TIME_SPAN_SECOND;
+
+ handler_id = cancellable ? g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (ecmb_wait_for_credentials_cancelled_cb), meta_backend) : 0;
+
+ while (wait_credentials_stamp == meta_backend->priv->wait_credentials_stamp &&
+ !g_cancellable_is_cancelled (cancellable)) {
+ if (!g_cond_wait_until (&meta_backend->priv->wait_credentials_cond,
&meta_backend->priv->wait_credentials_lock, wait_end_time))
+ break;
+ }
+
+ if (handler_id)
+ g_signal_handler_disconnect (cancellable, handler_id);
+
+ if (wait_credentials_stamp != meta_backend->priv->wait_credentials_stamp)
+ got_credentials = e_source_get_connection_status (e_backend_get_source (backend)) ==
E_SOURCE_CONNECTION_STATUS_CONNECTED;
+ } else {
+ g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ }
+
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ g_free (certificate_pem);
+
+ return got_credentials;
+}
+
+static void
e_cal_meta_backend_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -3073,6 +3184,8 @@ e_cal_meta_backend_finalize (GObject *object)
g_mutex_clear (&meta_backend->priv->connect_lock);
g_mutex_clear (&meta_backend->priv->property_lock);
+ g_mutex_clear (&meta_backend->priv->wait_credentials_lock);
+ g_cond_clear (&meta_backend->priv->wait_credentials_cond);
g_hash_table_destroy (meta_backend->priv->view_cancellables);
/* Chain up to parent's method. */
@@ -3093,6 +3206,7 @@ e_cal_meta_backend_class_init (ECalMetaBackendClass *klass)
klass->search_sync = ecmb_search_sync;
klass->search_components_sync = ecmb_search_components_sync;
klass->requires_reconnect = ecmb_requires_reconnect;
+ klass->get_ssl_error_details = ecmb_get_ssl_error_details;
cal_backend_sync_class = E_CAL_BACKEND_SYNC_CLASS (klass);
cal_backend_sync_class->open_sync = ecmb_open_sync;
@@ -3176,6 +3290,8 @@ e_cal_meta_backend_init (ECalMetaBackend *meta_backend)
g_mutex_init (&meta_backend->priv->connect_lock);
g_mutex_init (&meta_backend->priv->property_lock);
+ g_mutex_init (&meta_backend->priv->wait_credentials_lock);
+ g_cond_init (&meta_backend->priv->wait_credentials_cond);
meta_backend->priv->view_cancellables = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
g_object_unref);
meta_backend->priv->current_online_state = FALSE;
@@ -4515,6 +4631,9 @@ e_cal_meta_backend_get_changes_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
@@ -4528,16 +4647,36 @@ e_cal_meta_backend_get_changes_sync (ECalMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->get_changes_sync != NULL, FALSE);
- return klass->get_changes_sync (meta_backend,
- last_sync_tag,
- is_repeat,
- out_new_sync_tag,
- out_repeat,
- out_created_objects,
- out_modified_objects,
- out_removed_objects,
- cancellable,
- error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->get_changes_sync (meta_backend,
+ last_sync_tag,
+ is_repeat,
+ out_new_sync_tag,
+ out_repeat,
+ out_created_objects,
+ out_modified_objects,
+ out_removed_objects,
+ cancellable,
+ &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ecmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -4574,6 +4713,9 @@ e_cal_meta_backend_list_existing_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (out_existing_objects != NULL, FALSE);
@@ -4582,7 +4724,27 @@ e_cal_meta_backend_list_existing_sync (ECalMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->list_existing_sync != NULL, FALSE);
- return klass->list_existing_sync (meta_backend, out_new_sync_tag, out_existing_objects, cancellable,
error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->list_existing_sync (meta_backend, out_new_sync_tag, out_existing_objects,
cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ecmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -4623,6 +4785,9 @@ e_cal_meta_backend_load_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
@@ -4633,7 +4798,27 @@ e_cal_meta_backend_load_component_sync (ECalMetaBackend *meta_backend,
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->load_component_sync != NULL, FALSE);
- return klass->load_component_sync (meta_backend, uid, extra, out_component, out_extra, cancellable,
error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->load_component_sync (meta_backend, uid, extra, out_component, out_extra,
cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ecmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -4694,6 +4879,9 @@ e_cal_meta_backend_save_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (instances != NULL, FALSE);
@@ -4708,15 +4896,35 @@ e_cal_meta_backend_save_component_sync (ECalMetaBackend *meta_backend,
return FALSE;
}
- return klass->save_component_sync (meta_backend,
- overwrite_existing,
- conflict_resolution,
- instances,
- extra,
- out_new_uid,
- out_new_extra,
- cancellable,
- error);
+
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->save_component_sync (meta_backend,
+ overwrite_existing,
+ conflict_resolution,
+ instances,
+ extra,
+ out_new_uid,
+ out_new_extra,
+ cancellable,
+ &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ecmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -4750,6 +4958,9 @@ e_cal_meta_backend_remove_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalMetaBackendClass *klass;
+ gint repeat_count = 0;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
@@ -4762,7 +4973,26 @@ e_cal_meta_backend_remove_component_sync (ECalMetaBackend *meta_backend,
return FALSE;
}
- return klass->remove_component_sync (meta_backend, conflict_resolution, uid, extra, object,
cancellable, error);
+ while (!success && repeat_count <= MAX_REPEAT_COUNT) {
+ guint wait_credentials_stamp;
+
+ g_mutex_lock (&meta_backend->priv->wait_credentials_lock);
+ wait_credentials_stamp = meta_backend->priv->wait_credentials_stamp;
+ g_mutex_unlock (&meta_backend->priv->wait_credentials_lock);
+
+ g_clear_error (&local_error);
+ repeat_count++;
+
+ success = klass->remove_component_sync (meta_backend, conflict_resolution, uid, extra,
object, cancellable, &local_error);
+
+ if (!success && repeat_count <= MAX_REPEAT_COUNT && !ecmb_maybe_wait_for_credentials
(meta_backend, wait_credentials_stamp, local_error, cancellable))
+ break;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
/**
@@ -4881,3 +5111,34 @@ e_cal_meta_backend_requires_reconnect (ECalMetaBackend *meta_backend)
return klass->requires_reconnect (meta_backend);
}
+
+/**
+ * e_cal_meta_backend_get_ssl_error_details:
+ * @meta_backend: an #ECalMetaBackend
+ * @out_certificate_pem: (out): SSL certificate encoded in PEM format
+ * @out_certificate_errors: (out): bit-or of #GTlsCertificateFlags claiming the certificate errors
+ *
+ * It is optional to implement this virtual method by the descendants.
+ * It is used to receive SSL error details when any online operation
+ * returns E_DATA_CAL_ERROR, TLSNotAvailable error.
+ *
+ * Returns: %TRUE, when the SSL error details had been available and
+ * the out parameters populated, %FALSE otherwise.
+ *
+ * Since: 3.28
+ **/
+gboolean
+e_cal_meta_backend_get_ssl_error_details (ECalMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->get_ssl_error_details != NULL, FALSE);
+
+ return klass->get_ssl_error_details (meta_backend, out_certificate_pem, out_certificate_errors);
+}
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.h b/src/calendar/libedata-cal/e-cal-meta-backend.h
index 29e51be..4318e15 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.h
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.h
@@ -164,8 +164,12 @@ struct _ECalMetaBackendClass {
/* Signals */
void (* source_changed) (ECalMetaBackend *meta_backend);
+ gboolean (* get_ssl_error_details)
+ (ECalMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors);
/* Padding for future expansion */
- gpointer reserved[10];
+ gpointer reserved[9];
};
GType e_cal_meta_backend_get_type (void) G_GNUC_CONST;
@@ -301,6 +305,10 @@ gboolean e_cal_meta_backend_search_components_sync
GError **error);
gboolean e_cal_meta_backend_requires_reconnect
(ECalMetaBackend *meta_backend);
+gboolean e_cal_meta_backend_get_ssl_error_details
+ (ECalMetaBackend *meta_backend,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]