[evolution-data-server] [CalDAV] Race condition on connection object
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] [CalDAV] Race condition on connection object
- Date: Wed, 13 Jun 2018 15:40:05 +0000 (UTC)
commit 1d8db749060ebe807ad3d56c79326fc8509a3f54
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 13 17:38:41 2018 +0200
[CalDAV] Race condition on connection object
It could happen that one thread had been working with the connection
while another thread disconnected it, which could lead to a race
condition on the connection object, especially when the code execution
had been within that object.
The change makes sure to either add a reference on the connection
object while working with it or it adds a connection lock which is
acquired for the whole time when the connection object is used.
.../backends/google/e-book-backend-google.c | 64 +++++--
.../backends/webdav/e-book-backend-webdav.c | 164 +++++++++++++----
.../backends/caldav/e-cal-backend-caldav.c | 199 ++++++++++++++++-----
.../backends/gtasks/e-cal-backend-gtasks.c | 96 +++++++---
src/calendar/backends/http/e-cal-backend-http.c | 30 +++-
5 files changed, 427 insertions(+), 126 deletions(-)
---
diff --git a/src/addressbook/backends/google/e-book-backend-google.c
b/src/addressbook/backends/google/e-book-backend-google.c
index c6671005c..d627cb476 100644
--- a/src/addressbook/backends/google/e-book-backend-google.c
+++ b/src/addressbook/backends/google/e-book-backend-google.c
@@ -56,6 +56,7 @@ struct _EBookBackendGooglePrivate {
/* Did the server-side groups change? If so, re-download the book */
gboolean groups_changed;
+ GRecMutex conn_lock;
GDataAuthorizer *authorizer;
GDataService *service;
GHashTable *preloaded; /* gchar *uid ~> EContact * */
@@ -147,7 +148,7 @@ ebb_google_data_book_error_from_gdata_error (GError **error,
}
static gboolean
-ebb_google_is_authorized (EBookBackendGoogle *bbgoogle)
+ebb_google_is_authorized_locked (EBookBackendGoogle *bbgoogle)
{
g_return_val_if_fail (E_IS_BOOK_BACKEND_GOOGLE (bbgoogle), FALSE);
@@ -158,10 +159,10 @@ ebb_google_is_authorized (EBookBackendGoogle *bbgoogle)
}
static gboolean
-ebb_google_request_authorization (EBookBackendGoogle *bbgoogle,
- const ENamedParameters *credentials,
- GCancellable *cancellable,
- GError **error)
+ebb_google_request_authorization_locked (EBookBackendGoogle *bbgoogle,
+ const ENamedParameters *credentials,
+ GCancellable *cancellable,
+ GError **error)
{
/* Make sure we have the GDataService configured
* before requesting authorization. */
@@ -314,10 +315,10 @@ ebb_google_process_group (GDataEntry *entry,
}
static gboolean
-ebb_google_get_groups_sync (EBookBackendGoogle *bbgoogle,
- gboolean with_time_constraint,
- GCancellable *cancellable,
- GError **error)
+ebb_google_get_groups_locked_sync (EBookBackendGoogle *bbgoogle,
+ gboolean with_time_constraint,
+ GCancellable *cancellable,
+ GError **error)
{
GDataQuery *query;
GDataFeed *feed;
@@ -325,7 +326,7 @@ ebb_google_get_groups_sync (EBookBackendGoogle *bbgoogle,
GError *local_error = NULL;
g_return_val_if_fail (E_IS_BOOK_BACKEND_GOOGLE (bbgoogle), FALSE);
- g_return_val_if_fail (ebb_google_is_authorized (bbgoogle), FALSE);
+ g_return_val_if_fail (ebb_google_is_authorized_locked (bbgoogle), FALSE);
g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
@@ -390,15 +391,21 @@ ebb_google_connect_sync (EBookMetaBackend *meta_backend,
*out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
- if (ebb_google_is_authorized (bbgoogle))
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
+ if (ebb_google_is_authorized_locked (bbgoogle)) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
return TRUE;
+ }
- success = ebb_google_request_authorization (bbgoogle, credentials, cancellable, &local_error);
+ success = ebb_google_request_authorization_locked (bbgoogle, credentials, cancellable, &local_error);
if (success)
success = gdata_authorizer_refresh_authorization (bbgoogle->priv->authorizer, cancellable,
&local_error);
if (success)
- success = ebb_google_get_groups_sync (bbgoogle, FALSE, cancellable, &local_error);
+ success = ebb_google_get_groups_locked_sync (bbgoogle, FALSE, cancellable, &local_error);
+
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
if (!success) {
if (g_error_matches (local_error, GDATA_SERVICE_ERROR,
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
@@ -430,9 +437,13 @@ ebb_google_disconnect_sync (EBookMetaBackend *meta_backend,
bbgoogle = E_BOOK_BACKEND_GOOGLE (meta_backend);
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
g_clear_object (&bbgoogle->priv->service);
g_clear_object (&bbgoogle->priv->authorizer);
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
return TRUE;
}
@@ -469,8 +480,12 @@ ebb_google_get_changes_sync (EBookMetaBackend *meta_backend,
*out_modified_objects = NULL;
*out_removed_objects = NULL;
- if (!ebb_google_get_groups_sync (bbgoogle, TRUE, cancellable, error))
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
+ if (!ebb_google_get_groups_locked_sync (bbgoogle, TRUE, cancellable, error)) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
return FALSE;
+ }
book_cache = e_book_meta_backend_ref_cache (meta_backend);
@@ -657,6 +672,7 @@ ebb_google_get_changes_sync (EBookMetaBackend *meta_backend,
}
}
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
g_clear_object (&contacts_query);
g_clear_object (&feed);
@@ -766,10 +782,12 @@ ebb_google_create_group_sync (EBookBackendGoogle *bbgoogle,
gdata_entry_set_title (group, category_name);
/* Insert the new group */
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
new_group = GDATA_ENTRY (gdata_contacts_service_insert_group (
GDATA_CONTACTS_SERVICE (bbgoogle->priv->service),
GDATA_CONTACTS_GROUP (group),
cancellable, error));
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
g_object_unref (group);
if (new_group == NULL)
@@ -937,11 +955,12 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
if (extra && *extra)
entry = GDATA_ENTRY (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT, extra, -1,
NULL));
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
/* Ensure the system groups have been fetched. */
if (g_hash_table_size (bbgoogle->priv->system_groups_by_id) == 0)
- ebb_google_get_groups_sync (bbgoogle, FALSE, cancellable, NULL);
+ ebb_google_get_groups_locked_sync (bbgoogle, FALSE, cancellable, NULL);
if (overwrite_existing || entry) {
if (gdata_entry_update_from_e_contact (entry, contact, FALSE,
@@ -973,6 +992,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
g_clear_object (&book_cache);
if (!entry) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
g_propagate_error (error, e_data_book_create_error (E_DATA_BOOK_STATUS_OTHER_ERROR, _("Object
to save is not a valid vCard")));
return FALSE;
}
@@ -994,6 +1014,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
g_object_unref (entry);
if (!gdata_contact) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
ebb_google_data_book_error_from_gdata_error (error, local_error);
g_clear_error (&local_error);
e_contact_photo_free (photo);
@@ -1004,6 +1025,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
if (photo_changed) {
entry = ebb_google_update_contact_photo_sync (gdata_contact, GDATA_CONTACTS_SERVICE
(bbgoogle->priv->service), photo, cancellable, &local_error);
if (!entry) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
ebb_google_data_book_error_from_gdata_error (error, local_error);
g_clear_error (&local_error);
e_contact_photo_free (photo);
@@ -1016,6 +1038,8 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
gdata_contact = GDATA_CONTACTS_CONTACT (entry);
}
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
new_contact = e_contact_new_from_gdata_entry (GDATA_ENTRY (gdata_contact),
bbgoogle->priv->groups_by_id,
@@ -1085,9 +1109,12 @@ ebb_google_remove_contact_sync (EBookMetaBackend *meta_backend,
bbgoogle = E_BOOK_BACKEND_GOOGLE (meta_backend);
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
if (!gdata_service_delete_entry (bbgoogle->priv->service,
gdata_contacts_service_get_primary_authorization_domain (), entry,
cancellable, &local_error)) {
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
ebb_google_data_book_error_from_gdata_error (error, local_error);
g_error_free (local_error);
g_object_unref (entry);
@@ -1095,6 +1122,7 @@ ebb_google_remove_contact_sync (EBookMetaBackend *meta_backend,
return FALSE;
}
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
g_object_unref (entry);
return TRUE;
@@ -1273,9 +1301,13 @@ ebb_google_dispose (GObject *object)
{
EBookBackendGoogle *bbgoogle = E_BOOK_BACKEND_GOOGLE (object);
+ g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
g_clear_object (&bbgoogle->priv->service);
g_clear_object (&bbgoogle->priv->authorizer);
+ g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
g_hash_table_destroy (bbgoogle->priv->preloaded);
bbgoogle->priv->preloaded = NULL;
@@ -1295,6 +1327,7 @@ ebb_google_finalize (GObject *object)
g_clear_pointer (&bbgoogle->priv->system_groups_by_id, (GDestroyNotify) g_hash_table_destroy);
g_rec_mutex_clear (&bbgoogle->priv->groups_lock);
+ g_rec_mutex_clear (&bbgoogle->priv->conn_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object);
@@ -1307,6 +1340,7 @@ e_book_backend_google_init (EBookBackendGoogle *bbgoogle)
bbgoogle->priv->preloaded = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
g_rec_mutex_init (&bbgoogle->priv->groups_lock);
+ g_rec_mutex_init (&bbgoogle->priv->conn_lock);
bbgoogle->priv->groups_by_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
bbgoogle->priv->groups_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
diff --git a/src/addressbook/backends/webdav/e-book-backend-webdav.c
b/src/addressbook/backends/webdav/e-book-backend-webdav.c
index de5ebfe26..94d198bb7 100644
--- a/src/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/src/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -38,6 +38,7 @@
struct _EBookBackendWebDAVPrivate {
/* The main WebDAV session */
EWebDAVSession *webdav;
+ GMutex webdav_lock;
/* support for 'getctag' extension */
gboolean ctag_supported;
@@ -48,6 +49,23 @@ struct _EBookBackendWebDAVPrivate {
G_DEFINE_TYPE (EBookBackendWebDAV, e_book_backend_webdav, E_TYPE_BOOK_META_BACKEND)
+static EWebDAVSession *
+ebb_webdav_ref_session (EBookBackendWebDAV *bbdav)
+{
+ EWebDAVSession *webdav;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (bbdav), NULL);
+
+ g_mutex_lock (&bbdav->priv->webdav_lock);
+ if (bbdav->priv->webdav)
+ webdav = g_object_ref (bbdav->priv->webdav);
+ else
+ webdav = NULL;
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
+
+ return webdav;
+}
+
static gboolean
ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
const ENamedParameters *credentials,
@@ -58,6 +76,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
GHashTable *capabilities = NULL, *allows = NULL;
ESource *source;
gboolean success, is_writable = FALSE;
@@ -68,18 +87,22 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
- if (bbdav->priv->webdav)
+ g_mutex_lock (&bbdav->priv->webdav_lock);
+ if (bbdav->priv->webdav) {
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
return TRUE;
+ }
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
source = e_backend_get_source (E_BACKEND (meta_backend));
- bbdav->priv->webdav = e_webdav_session_new (source);
+ webdav = e_webdav_session_new (source);
- e_soup_session_setup_logging (E_SOUP_SESSION (bbdav->priv->webdav), g_getenv ("WEBDAV_DEBUG"));
+ e_soup_session_setup_logging (E_SOUP_SESSION (webdav), g_getenv ("WEBDAV_DEBUG"));
e_binding_bind_property (
bbdav, "proxy-resolver",
- bbdav->priv->webdav, "proxy-resolver",
+ webdav, "proxy-resolver",
G_BINDING_SYNC_CREATE);
/* Thinks the 'getctag' extension is available the first time, but unset it when realizes it isn't. */
@@ -87,9 +110,9 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
- e_soup_session_set_credentials (E_SOUP_SESSION (bbdav->priv->webdav), credentials);
+ e_soup_session_set_credentials (E_SOUP_SESSION (webdav), credentials);
- success = e_webdav_session_options_sync (bbdav->priv->webdav, NULL,
+ success = e_webdav_session_options_sync (webdav, NULL,
&capabilities, &allows, cancellable, &local_error);
/* iCloud and Google servers can return "404 Not Found" when issued OPTIONS on the addressbook
collection */
@@ -119,7 +142,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
if (uri) {
g_clear_error (&local_error);
- success = e_webdav_session_options_sync (bbdav->priv->webdav,
uri,
+ success = e_webdav_session_options_sync (webdav, uri,
&capabilities, &allows, cancellable, &local_error);
}
@@ -147,7 +170,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
GSList *privileges = NULL, *link;
/* Ignore any errors here */
- if (e_webdav_session_get_current_user_privilege_set_sync (bbdav->priv->webdav, NULL,
&privileges, cancellable, NULL)) {
+ if (e_webdav_session_get_current_user_privilege_set_sync (webdav, NULL, &privileges,
cancellable, NULL)) {
for (link = privileges; link && !is_writable; link = g_slist_next (link)) {
EWebDAVPrivilege *privilege = link->data;
@@ -213,7 +236,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
The 'getctag' extension is not required, thuch check
for unauthorized error only. */
- if (!e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &ctag, cancellable,
&local_error) &&
+ if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
success = FALSE;
} else {
@@ -230,7 +253,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
gboolean is_ssl_error;
credentials_empty = (!credentials || !e_named_parameters_count (credentials)) &&
- e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION
(bbdav->priv->webdav));
+ e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav));
is_ssl_error = g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED);
*out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
@@ -247,7 +270,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
else
*out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
} else if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED) ||
- (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION
(bbdav->priv->webdav)) &&
+ (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav))
&&
g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))) {
*out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
} else if (!local_error) {
@@ -264,7 +287,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
*out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
- e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+ e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem,
out_certificate_errors);
} else {
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
}
@@ -275,8 +298,18 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
if (allows)
g_hash_table_destroy (allows);
- if (!success)
- g_clear_object (&bbdav->priv->webdav);
+ if (success && !g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ g_mutex_lock (&bbdav->priv->webdav_lock);
+ bbdav->priv->webdav = webdav;
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
+ } else {
+ if (success) {
+ e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+ success = FALSE;
+ }
+
+ g_clear_object (&webdav);
+ }
return success;
}
@@ -293,11 +326,15 @@ ebb_webdav_disconnect_sync (EBookMetaBackend *meta_backend,
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+ g_mutex_lock (&bbdav->priv->webdav_lock);
+
if (bbdav->priv->webdav)
soup_session_abort (SOUP_SESSION (bbdav->priv->webdav));
g_clear_object (&bbdav->priv->webdav);
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
+
source = e_backend_get_source (E_BACKEND (meta_backend));
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
@@ -403,6 +440,7 @@ ebb_webdav_multiget_response_cb (EWebDAVSession *webdav,
static gboolean
ebb_webdav_multiget_from_sets_sync (EBookBackendWebDAV *bbdav,
+ EWebDAVSession *webdav,
GSList **in_link,
GSList **set2,
GCancellable *cancellable,
@@ -461,7 +499,7 @@ ebb_webdav_multiget_from_sets_sync (EBookBackendWebDAV *bbdav,
if (left_to_go != E_WEBDAV_MAX_MULTIGET_AMOUNT && success) {
GSList *from_link = *in_link;
- success = e_webdav_session_report_sync (bbdav->priv->webdav, NULL, NULL, xml,
+ success = e_webdav_session_report_sync (webdav, NULL, NULL, xml,
ebb_webdav_multiget_response_cb, &from_link, NULL, NULL, cancellable, error);
}
@@ -565,11 +603,12 @@ ebb_webdav_search_changes_cb (EBookCache *book_cache,
static void
ebb_webdav_check_credentials_error (EBookBackendWebDAV *bbdav,
+ EWebDAVSession *webdav,
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) {
+ if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && 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) ||
@@ -577,10 +616,10 @@ ebb_webdav_check_credentials_error (EBookBackendWebDAV *bbdav,
op_error->domain = E_DATA_BOOK_ERROR;
op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
- if (bbdav->priv->webdav) {
+ if (webdav) {
ENamedParameters *credentials;
- credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (bbdav->priv->webdav));
+ credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
if (credentials && e_named_parameters_count (credentials) > 0)
op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED;
@@ -602,6 +641,7 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
EXmlDocument *xml;
GHashTable *known_items; /* gchar *href ~> EBookMetaBackendInfo * */
GHashTableIter iter;
@@ -621,17 +661,21 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
*out_removed_objects = NULL;
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+ webdav = ebb_webdav_ref_session (bbdav);
if (bbdav->priv->ctag_supported) {
gchar *new_sync_tag = NULL;
- success = e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &new_sync_tag,
cancellable, NULL);
+ success = e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL);
if (!success) {
bbdav->priv->ctag_supported = g_cancellable_set_error_if_cancelled (cancellable,
error);
- if (bbdav->priv->ctag_supported || !bbdav->priv->webdav)
+ if (bbdav->priv->ctag_supported || !webdav) {
+ g_clear_object (&webdav);
return FALSE;
+ }
} else if (new_sync_tag && last_sync_tag && g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
*out_new_sync_tag = new_sync_tag;
+ g_clear_object (&webdav);
return TRUE;
}
@@ -647,7 +691,7 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
known_items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_book_meta_backend_info_free);
- success = e_webdav_session_propfind_sync (bbdav->priv->webdav, NULL,
E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
+ success = e_webdav_session_propfind_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
ebb_webdav_get_contact_items_cb, known_items, cancellable, &local_error);
g_object_unref (xml);
@@ -687,15 +731,17 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
}
do {
- success = ebb_webdav_multiget_from_sets_sync (bbdav, &link, &set2, cancellable,
&local_error);
+ success = ebb_webdav_multiget_from_sets_sync (bbdav, webdav, &link, &set2,
cancellable, &local_error);
} while (success && link);
}
if (local_error) {
- ebb_webdav_check_credentials_error (bbdav, local_error);
+ ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -757,6 +803,7 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
EXmlDocument *xml;
GError *local_error = NULL;
gboolean success;
@@ -785,7 +832,9 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
e_xml_document_end_element (xml); /* address-data */
e_xml_document_end_element (xml); /* prop */
- success = e_webdav_session_report_sync (bbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+ webdav = ebb_webdav_ref_session (bbdav);
+
+ success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
ebb_webdav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
g_object_unref (xml);
@@ -794,10 +843,12 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
*out_existing_objects = g_slist_reverse (*out_existing_objects);
if (local_error) {
- ebb_webdav_check_credentials_error (bbdav, local_error);
+ ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -869,6 +920,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
gchar *uri = NULL, *href = NULL, *etag = NULL, *bytes = NULL;
gsize length = -1;
gboolean success = FALSE;
@@ -879,11 +931,12 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
g_return_val_if_fail (out_contact != NULL, FALSE);
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+ webdav = ebb_webdav_ref_session (bbdav);
if (extra && *extra) {
uri = g_strdup (extra);
- success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length,
cancellable, &local_error);
if (!success) {
g_free (uri);
@@ -894,13 +947,14 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
if (!success && bbdav->priv->ctag_supported) {
gchar *new_sync_tag = NULL;
- if (e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &new_sync_tag, cancellable,
NULL) && new_sync_tag) {
+ if (e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL) &&
new_sync_tag) {
gchar *last_sync_tag;
last_sync_tag = e_book_meta_backend_dup_sync_tag (meta_backend);
/* The book didn't change, thus the contact cannot be there */
if (g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
+ g_clear_object (&webdav);
g_clear_error (&local_error);
g_free (last_sync_tag);
g_free (new_sync_tag);
@@ -922,7 +976,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
g_clear_error (&local_error);
- success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length,
cancellable, &local_error);
/* Do not try twice with Google, it's either without extension or not there.
The worst, it counts to the Error requests quota limit. */
@@ -934,7 +988,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
if (uri) {
g_clear_error (&local_error);
- success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href,
&etag, &bytes, &length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
}
}
}
@@ -964,10 +1018,12 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
g_free (bytes);
if (local_error) {
- ebb_webdav_check_credentials_error (bbdav, local_error);
+ ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -983,6 +1039,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
gchar *href = NULL, *etag = NULL, *uid = NULL;
gchar *vcard_string = NULL;
GError *local_error = NULL;
@@ -994,6 +1051,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
g_return_val_if_fail (out_new_extra, FALSE);
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+ webdav = ebb_webdav_ref_session (bbdav);
uid = e_contact_get (contact, E_CONTACT_UID);
etag = e_vcard_util_dup_x_attribute (E_VCARD (contact), E_WEBDAV_X_ETAG);
@@ -1021,7 +1079,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
}
}
- success = e_webdav_session_put_data_sync (bbdav->priv->webdav, (extra && *extra) ? extra :
href,
+ success = e_webdav_session_put_data_sync (webdav, (extra && *extra) ? extra : href,
force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_VCARD,
vcard_string, -1, out_new_extra, NULL, cancellable, &local_error);
@@ -1039,10 +1097,12 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
g_free (uid);
if (local_error) {
- ebb_webdav_check_credentials_error (bbdav, local_error);
+ ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1056,6 +1116,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
GError **error)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
EContact *contact;
gchar *etag = NULL;
gboolean success;
@@ -1081,7 +1142,9 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
if (conflict_resolution == E_CONFLICT_RESOLUTION_FAIL)
etag = e_vcard_util_dup_x_attribute (E_VCARD (contact), E_WEBDAV_X_ETAG);
- success = e_webdav_session_delete_sync (bbdav->priv->webdav, extra,
+ webdav = ebb_webdav_ref_session (bbdav);
+
+ success = e_webdav_session_delete_sync (webdav, extra,
NULL, etag, cancellable, &local_error);
if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
@@ -1090,7 +1153,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
href = ebb_webdav_uid_to_uri (bbdav, uid, ".vcf");
if (href) {
g_clear_error (&local_error);
- success = e_webdav_session_delete_sync (bbdav->priv->webdav, href,
+ success = e_webdav_session_delete_sync (webdav, href,
NULL, etag, cancellable, &local_error);
g_free (href);
@@ -1100,7 +1163,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
href = ebb_webdav_uid_to_uri (bbdav, uid, NULL);
if (href) {
g_clear_error (&local_error);
- success = e_webdav_session_delete_sync (bbdav->priv->webdav, href,
+ success = e_webdav_session_delete_sync (webdav, href,
NULL, etag, cancellable, &local_error);
g_free (href);
@@ -1112,10 +1175,12 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
g_free (etag);
if (local_error) {
- ebb_webdav_check_credentials_error (bbdav, local_error);
+ ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1125,15 +1190,22 @@ ebb_webdav_get_ssl_error_details (EBookMetaBackend *meta_backend,
GTlsCertificateFlags *out_certificate_errors)
{
EBookBackendWebDAV *bbdav;
+ EWebDAVSession *webdav;
+ gboolean res;
g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (meta_backend), FALSE);
bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+ webdav = ebb_webdav_ref_session (bbdav);
- if (!bbdav->priv->webdav)
+ if (!webdav)
return FALSE;
- return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+ res = e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem,
out_certificate_errors);
+
+ g_clear_object (&webdav);
+
+ return res;
}
static gchar *
@@ -1187,16 +1259,31 @@ e_book_backend_webdav_dispose (GObject *object)
{
EBookBackendWebDAV *bbdav = E_BOOK_BACKEND_WEBDAV (object);
+ g_mutex_lock (&bbdav->priv->webdav_lock);
g_clear_object (&bbdav->priv->webdav);
+ g_mutex_unlock (&bbdav->priv->webdav_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->dispose (object);
}
+static void
+e_book_backend_webdav_finalize (GObject *object)
+{
+ EBookBackendWebDAV *bbdav = E_BOOK_BACKEND_WEBDAV (object);
+
+ g_mutex_clear (&bbdav->priv->webdav_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->finalize (object);
+}
+
static void
e_book_backend_webdav_init (EBookBackendWebDAV *bbdav)
{
bbdav->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbdav, E_TYPE_BOOK_BACKEND_WEBDAV,
EBookBackendWebDAVPrivate);
+
+ g_mutex_init (&bbdav->priv->webdav_lock);
}
static void
@@ -1226,4 +1313,5 @@ e_book_backend_webdav_class_init (EBookBackendWebDAVClass *klass)
object_class = G_OBJECT_CLASS (klass);
object_class->constructed = e_book_backend_webdav_constructed;
object_class->dispose = e_book_backend_webdav_dispose;
+ object_class->finalize = e_book_backend_webdav_finalize;
}
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 23ef90bb0..fc9d5539a 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -36,6 +36,7 @@
struct _ECalBackendCalDAVPrivate {
/* The main WebDAV session */
EWebDAVSession *webdav;
+ GMutex webdav_lock;
/* support for 'getctag' extension */
gboolean ctag_supported;
@@ -58,6 +59,23 @@ struct _ECalBackendCalDAVPrivate {
G_DEFINE_TYPE (ECalBackendCalDAV, e_cal_backend_caldav, E_TYPE_CAL_META_BACKEND)
+static EWebDAVSession *
+ecb_caldav_ref_session (ECalBackendCalDAV *cbdav)
+{
+ EWebDAVSession *webdav;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav), NULL);
+
+ g_mutex_lock (&cbdav->priv->webdav_lock);
+ if (cbdav->priv->webdav)
+ webdav = g_object_ref (cbdav->priv->webdav);
+ else
+ webdav = NULL;
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
+
+ return webdav;
+}
+
static void
ecb_caldav_update_tweaks (ECalBackendCalDAV *cbdav)
{
@@ -95,6 +113,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
GHashTable *capabilities = NULL, *allows = NULL;
ESource *source;
gboolean success, is_writable = FALSE;
@@ -105,18 +124,22 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
- if (cbdav->priv->webdav)
+ g_mutex_lock (&cbdav->priv->webdav_lock);
+ if (cbdav->priv->webdav) {
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
return TRUE;
+ }
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
source = e_backend_get_source (E_BACKEND (meta_backend));
- cbdav->priv->webdav = e_webdav_session_new (source);
+ webdav = e_webdav_session_new (source);
- e_soup_session_setup_logging (E_SOUP_SESSION (cbdav->priv->webdav), g_getenv ("CALDAV_DEBUG"));
+ e_soup_session_setup_logging (E_SOUP_SESSION (webdav), g_getenv ("CALDAV_DEBUG"));
e_binding_bind_property (
cbdav, "proxy-resolver",
- cbdav->priv->webdav, "proxy-resolver",
+ webdav, "proxy-resolver",
G_BINDING_SYNC_CREATE);
/* Thinks the 'getctag' extension is available the first time, but unset it when realizes it isn't. */
@@ -124,16 +147,16 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
- e_soup_session_set_credentials (E_SOUP_SESSION (cbdav->priv->webdav), credentials);
+ e_soup_session_set_credentials (E_SOUP_SESSION (webdav), credentials);
- success = e_webdav_session_options_sync (cbdav->priv->webdav, NULL,
+ success = e_webdav_session_options_sync (webdav, NULL,
&capabilities, &allows, cancellable, &local_error);
if (success && !g_cancellable_is_cancelled (cancellable)) {
GSList *privileges = NULL, *link;
/* Ignore any errors here */
- if (e_webdav_session_get_current_user_privilege_set_sync (cbdav->priv->webdav, NULL,
&privileges, cancellable, NULL)) {
+ if (e_webdav_session_get_current_user_privilege_set_sync (webdav, NULL, &privileges,
cancellable, NULL)) {
for (link = privileges; link && !is_writable; link = g_slist_next (link)) {
EWebDAVPrivilege *privilege = link->data;
@@ -199,7 +222,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
The 'getctag' extension is not required, thuch check
for unauthorized error only. */
- if (!e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &ctag, cancellable,
&local_error) &&
+ if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
success = FALSE;
} else {
@@ -214,7 +237,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
gboolean is_ssl_error;
credentials_empty = (!credentials || !e_named_parameters_count (credentials)) &&
- e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION
(cbdav->priv->webdav));
+ e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav));
is_ssl_error = g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED);
*out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
@@ -231,7 +254,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
else
*out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
} else if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED) ||
- (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION
(cbdav->priv->webdav)) &&
+ (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav))
&&
g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))) {
*out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
} else if (!local_error) {
@@ -248,7 +271,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
*out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
- e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+ e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem,
out_certificate_errors);
} else {
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
}
@@ -259,8 +282,18 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
if (allows)
g_hash_table_destroy (allows);
- if (!success)
- g_clear_object (&cbdav->priv->webdav);
+ if (success && !g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ g_mutex_lock (&cbdav->priv->webdav_lock);
+ cbdav->priv->webdav = webdav;
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
+ } else {
+ if (success) {
+ e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+ success = FALSE;
+ }
+
+ g_clear_object (&webdav);
+ }
return success;
}
@@ -277,10 +310,12 @@ ecb_caldav_disconnect_sync (ECalMetaBackend *meta_backend,
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+ g_mutex_lock (&cbdav->priv->webdav_lock);
if (cbdav->priv->webdav)
soup_session_abort (SOUP_SESSION (cbdav->priv->webdav));
g_clear_object (&cbdav->priv->webdav);
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
source = e_backend_get_source (E_BACKEND (meta_backend));
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
@@ -424,6 +459,7 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
static gboolean
ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
+ EWebDAVSession *webdav,
GSList **in_link,
GSList **set2,
GCancellable *cancellable,
@@ -470,7 +506,7 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
if (cbdav->priv->is_icloud) {
gchar *calendar_data = NULL, *etag = NULL;
- success = e_webdav_session_get_data_sync (cbdav->priv->webdav,
+ success = e_webdav_session_get_data_sync (webdav,
nfo->extra, NULL, &etag, &calendar_data, NULL, cancellable, error);
if (success && calendar_data) {
@@ -510,7 +546,7 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
!cbdav->priv->is_icloud && success) {
GSList *from_link = *in_link;
- success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, NULL, xml,
+ success = e_webdav_session_report_sync (webdav, NULL, NULL, xml,
ecb_caldav_multiget_response_cb, &from_link, NULL, NULL, cancellable, error);
}
@@ -616,11 +652,12 @@ ecb_caldav_search_changes_cb (ECalCache *cal_cache,
static void
ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
+ EWebDAVSession *webdav,
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) {
+ if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && 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) ||
@@ -628,10 +665,10 @@ ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
op_error->domain = E_DATA_CAL_ERROR;
op_error->code = AuthenticationRequired;
- if (cbdav->priv->webdav) {
+ if (webdav) {
ENamedParameters *credentials;
- credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (cbdav->priv->webdav));
+ credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
if (credentials && e_named_parameters_count (credentials) > 0)
op_error->code = AuthenticationFailed;
@@ -653,6 +690,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
EXmlDocument *xml;
GHashTable *known_items; /* gchar *href ~> ECalMetaBackendInfo * */
GHashTableIter iter;
@@ -673,17 +711,21 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
*out_removed_objects = NULL;
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+ webdav = ecb_caldav_ref_session (cbdav);
if (cbdav->priv->ctag_supported) {
gchar *new_sync_tag = NULL;
- success = e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &new_sync_tag,
cancellable, NULL);
+ success = e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL);
if (!success) {
cbdav->priv->ctag_supported = g_cancellable_set_error_if_cancelled (cancellable,
error);
- if (cbdav->priv->ctag_supported || !cbdav->priv->webdav)
+ if (cbdav->priv->ctag_supported || !webdav) {
+ g_clear_object (&webdav);
return FALSE;
+ }
} else if (!is_repeat && new_sync_tag && last_sync_tag && g_strcmp0 (last_sync_tag,
new_sync_tag) == 0) {
*out_new_sync_tag = new_sync_tag;
+ g_clear_object (&webdav);
return TRUE;
}
@@ -752,7 +794,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
known_items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_cal_meta_backend_info_free);
- success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
xml,
+ success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
ecb_caldav_get_calendar_items_cb, known_items, NULL, NULL, cancellable, &local_error);
g_object_unref (xml);
@@ -793,15 +835,17 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
}
do {
- success = ecb_caldav_multiget_from_sets_sync (cbdav, &link, &set2, cancellable,
&local_error);
+ success = ecb_caldav_multiget_from_sets_sync (cbdav, webdav, &link, &set2,
cancellable, &local_error);
} while (success && link);
}
if (local_error) {
- ecb_caldav_check_credentials_error (cbdav, local_error);
+ ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -863,6 +907,7 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
icalcomponent_kind kind;
EXmlDocument *xml;
GError *local_error = NULL;
@@ -874,6 +919,7 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
*out_existing_objects = NULL;
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+
kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbdav));
xml = e_xml_document_new (E_WEBDAV_NS_CALDAV, "calendar-query");
@@ -917,7 +963,9 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
e_xml_document_end_element (xml); /* comp-filter / VCALENDAR */
e_xml_document_end_element (xml); /* filter */
- success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+ webdav = ecb_caldav_ref_session (cbdav);
+
+ success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
ecb_caldav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
g_object_unref (xml);
@@ -926,10 +974,12 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
*out_existing_objects = g_slist_reverse (*out_existing_objects);
if (local_error) {
- ecb_caldav_check_credentials_error (cbdav, local_error);
+ ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1000,6 +1050,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
gchar *uri = NULL, *href = NULL, *etag = NULL, *bytes = NULL;
gsize length = -1;
gboolean success = FALSE;
@@ -1010,11 +1061,12 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
g_return_val_if_fail (out_component != NULL, FALSE);
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+ webdav = ecb_caldav_ref_session (cbdav);
if (extra && *extra) {
uri = g_strdup (extra);
- success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length,
cancellable, &local_error);
if (!success) {
g_free (uri);
@@ -1025,7 +1077,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
if (!success && cbdav->priv->ctag_supported) {
gchar *new_sync_tag = NULL;
- if (e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &new_sync_tag, cancellable,
NULL) && new_sync_tag) {
+ if (e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL) &&
new_sync_tag) {
gchar *last_sync_tag;
last_sync_tag = e_cal_meta_backend_dup_sync_tag (meta_backend);
@@ -1033,6 +1085,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
/* The calendar didn't change, thus the component cannot be there */
if (g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
g_clear_error (&local_error);
+ g_clear_object (&webdav);
g_free (last_sync_tag);
g_free (new_sync_tag);
@@ -1053,7 +1106,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
g_clear_error (&local_error);
- success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length,
cancellable, &local_error);
/* Do not try twice with Google, it's either with ".ics" extension or not there.
The worst, it counts to the Error requests quota limit. */
@@ -1065,7 +1118,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
if (uri) {
g_clear_error (&local_error);
- success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href,
&etag, &bytes, &length, cancellable, &local_error);
+ success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes,
&length, cancellable, &local_error);
}
}
}
@@ -1108,10 +1161,12 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
g_free (bytes);
if (local_error) {
- ecb_caldav_check_credentials_error (cbdav, local_error);
+ ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1127,6 +1182,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
icalcomponent *vcalendar, *subcomp;
gchar *href = NULL, *etag = NULL, *uid = NULL;
gchar *ical_string = NULL;
@@ -1163,6 +1219,8 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
ical_string = icalcomponent_as_ical_string_r (vcalendar);
icalcomponent_free (vcalendar);
+ webdav = ecb_caldav_ref_session (cbdav);
+
if (uid && ical_string && (!overwrite_existing || (extra && *extra))) {
gboolean force_write = FALSE;
@@ -1182,7 +1240,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
}
}
- success = e_webdav_session_put_data_sync (cbdav->priv->webdav, (extra && *extra) ? extra :
href,
+ success = e_webdav_session_put_data_sync (webdav, (extra && *extra) ? extra : href,
force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_CALENDAR,
ical_string, -1, out_new_extra, NULL, cancellable, &local_error);
@@ -1200,10 +1258,12 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
g_free (uid);
if (local_error) {
- ecb_caldav_check_credentials_error (cbdav, local_error);
+ ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1217,6 +1277,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
icalcomponent *icalcomp;
gchar *etag = NULL;
gboolean success;
@@ -1242,7 +1303,9 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
if (conflict_resolution == E_CONFLICT_RESOLUTION_FAIL)
etag = e_cal_util_dup_x_property (icalcomp, E_CALDAV_X_ETAG);
- success = e_webdav_session_delete_sync (cbdav->priv->webdav, extra,
+ webdav = ecb_caldav_ref_session (cbdav);
+
+ success = e_webdav_session_delete_sync (webdav, extra,
NULL, etag, cancellable, &local_error);
if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
@@ -1251,7 +1314,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
href = ecb_caldav_uid_to_uri (cbdav, uid, ".ics");
if (href) {
g_clear_error (&local_error);
- success = e_webdav_session_delete_sync (cbdav->priv->webdav, href,
+ success = e_webdav_session_delete_sync (webdav, href,
NULL, etag, cancellable, &local_error);
g_free (href);
@@ -1261,7 +1324,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
href = ecb_caldav_uid_to_uri (cbdav, uid, NULL);
if (href) {
g_clear_error (&local_error);
- success = e_webdav_session_delete_sync (cbdav->priv->webdav, href,
+ success = e_webdav_session_delete_sync (webdav, href,
NULL, etag, cancellable, &local_error);
g_free (href);
@@ -1273,10 +1336,12 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
g_free (etag);
if (local_error) {
- ecb_caldav_check_credentials_error (cbdav, local_error);
+ ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
g_propagate_error (error, local_error);
}
+ g_clear_object (&webdav);
+
return success;
}
@@ -1286,15 +1351,22 @@ ecb_caldav_get_ssl_error_details (ECalMetaBackend *meta_backend,
GTlsCertificateFlags *out_certificate_errors)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
+ gboolean res;
g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (meta_backend), FALSE);
cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+ webdav = ecb_caldav_ref_session (cbdav);
- if (!cbdav->priv->webdav)
+ if (!webdav)
return FALSE;
- return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav),
out_certificate_pem, out_certificate_errors);
+ res = e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem,
out_certificate_errors);
+
+ g_clear_object (&webdav);
+
+ return res;
}
static gboolean
@@ -1360,6 +1432,7 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
GError **error)
{
EXmlDocument *xml;
+ EWebDAVSession *webdav;
gchar *owner_href = NULL, *schedule_outbox_url = NULL;
gboolean success;
@@ -1373,12 +1446,15 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
e_xml_document_add_empty_element (xml, NULL, "owner");
e_xml_document_end_element (xml); /* prop */
- success = e_webdav_session_propfind_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+ webdav = ecb_caldav_ref_session (cbdav);
+
+ success = e_webdav_session_propfind_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
ecb_caldav_propfind_get_owner_cb, &owner_href, cancellable, error);
g_object_unref (xml);
if (!success || !owner_href || !*owner_href) {
+ g_clear_object (&webdav);
g_free (owner_href);
return FALSE;
}
@@ -1386,6 +1462,7 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
xml = e_xml_document_new (E_WEBDAV_NS_DAV, "propfind");
if (!xml) {
g_warn_if_fail (xml != NULL);
+ g_clear_object (&webdav);
g_free (owner_href);
return FALSE;
}
@@ -1396,9 +1473,10 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
e_xml_document_add_empty_element (xml, E_WEBDAV_NS_CALDAV, "schedule-outbox-URL");
e_xml_document_end_element (xml); /* prop */
- success = e_webdav_session_propfind_sync (cbdav->priv->webdav, owner_href, E_WEBDAV_DEPTH_THIS, xml,
+ success = e_webdav_session_propfind_sync (webdav, owner_href, E_WEBDAV_DEPTH_THIS, xml,
ecb_caldav_propfind_get_schedule_outbox_url_cb, &schedule_outbox_url, cancellable, error);
+ g_clear_object (&webdav);
g_object_unref (xml);
g_free (owner_href);
@@ -1526,6 +1604,7 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
ECalComponentOrganizer organizer = { NULL };
ESourceAuthentication *auth_extension;
ESource *source;
+ EWebDAVSession *webdav;
struct icaltimetype dtvalue;
icaltimezone *utc;
gchar *str;
@@ -1620,7 +1699,9 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
icalcomponent_free (icalcomp);
g_object_unref (comp);
- if (e_webdav_session_post_sync (cbdav->priv->webdav, cbdav->priv->schedule_outbox_url, str, -1, NULL,
&response, cancellable, &local_error) &&
+ webdav = ecb_caldav_ref_session (cbdav);
+
+ if (e_webdav_session_post_sync (webdav, cbdav->priv->schedule_outbox_url, str, -1, NULL, &response,
cancellable, &local_error) &&
response) {
/* parse returned xml */
xmlDocPtr doc;
@@ -1689,6 +1770,7 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
xmlFreeDoc (doc);
}
+ g_clear_object (&webdav);
if (response)
g_byte_array_free (response, TRUE);
g_free (str);
@@ -1708,6 +1790,7 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
GCancellable *cancellable,
GError **error)
{
+ EWebDAVSession *webdav;
EWebDAVResource *resource;
GSList *principals = NULL;
EXmlDocument *xml;
@@ -1720,13 +1803,17 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
g_return_val_if_fail (usermail != NULL, FALSE);
g_return_val_if_fail (out_freebusy != NULL, FALSE);
- if (!e_webdav_session_principal_property_search_sync (cbdav->priv->webdav, NULL, TRUE,
+ webdav = ecb_caldav_ref_session (cbdav);
+
+ if (!e_webdav_session_principal_property_search_sync (webdav, NULL, TRUE,
E_WEBDAV_NS_CALDAV, "calendar-user-address-set", usermail, &principals, cancellable, error)) {
+ g_clear_object (&webdav);
return FALSE;
}
if (!principals || principals->next || !principals->data) {
g_slist_free_full (principals, e_webdav_resource_free);
+ g_clear_object (&webdav);
return FALSE;
}
@@ -1736,6 +1823,7 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
g_slist_free_full (principals, e_webdav_resource_free);
if (!href || !*href) {
+ g_clear_object (&webdav);
g_free (href);
return FALSE;
}
@@ -1747,8 +1835,9 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
e_xml_document_add_attribute_time (xml, NULL, "end", end);
e_xml_document_end_element (xml); /* time-range */
- success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_INFINITY, xml,
NULL, NULL, &content_type, &content, cancellable, error);
+ success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_INFINITY, xml, NULL, NULL,
&content_type, &content, cancellable, error);
+ g_clear_object (&webdav);
g_object_unref (xml);
if (success && content_type && content && content->data && content->len &&
@@ -1811,24 +1900,29 @@ ecb_caldav_get_free_busy_sync (ECalBackendSync *sync_backend,
GError **error)
{
ECalBackendCalDAV *cbdav;
+ EWebDAVSession *webdav;
g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (sync_backend));
g_return_if_fail (out_freebusy != NULL);
cbdav = E_CAL_BACKEND_CALDAV (sync_backend);
+ webdav = ecb_caldav_ref_session (cbdav);
- if (e_backend_get_online (E_BACKEND (cbdav)) &&
- cbdav->priv->webdav) {
+ if (e_backend_get_online (E_BACKEND (cbdav)) && webdav) {
const GSList *link;
GError *local_error = NULL;
- if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end,
out_freebusy, cancellable, &local_error))
+ if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end,
out_freebusy, cancellable, &local_error)) {
+ g_clear_object (&webdav);
return;
+ }
g_clear_error (&local_error);
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ g_clear_object (&webdav);
return;
+ }
*out_freebusy = NULL;
@@ -1839,10 +1933,14 @@ ecb_caldav_get_free_busy_sync (ECalBackendSync *sync_backend,
g_clear_error (&local_error);
- if (*out_freebusy || g_cancellable_set_error_if_cancelled (cancellable, error))
+ if (*out_freebusy || g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ g_clear_object (&webdav);
return;
+ }
}
+ g_clear_object (&webdav);
+
/* Chain up to parent's method. */
E_CAL_BACKEND_SYNC_CLASS (e_cal_backend_caldav_parent_class)->get_free_busy_sync (sync_backend, cal,
cancellable,
users, start, end, out_freebusy, error);
@@ -1928,7 +2026,9 @@ e_cal_backend_caldav_dispose (GObject *object)
{
ECalBackendCalDAV *cbdav = E_CAL_BACKEND_CALDAV (object);
+ g_mutex_lock (&cbdav->priv->webdav_lock);
g_clear_object (&cbdav->priv->webdav);
+ g_mutex_unlock (&cbdav->priv->webdav_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_caldav_parent_class)->dispose (object);
@@ -1940,6 +2040,7 @@ e_cal_backend_caldav_finalize (GObject *object)
ECalBackendCalDAV *cbdav = E_CAL_BACKEND_CALDAV (object);
g_clear_pointer (&cbdav->priv->schedule_outbox_url, g_free);
+ g_mutex_clear (&cbdav->priv->webdav_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_caldav_parent_class)->finalize (object);
@@ -1949,6 +2050,8 @@ static void
e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
{
cbdav->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbdav, E_TYPE_CAL_BACKEND_CALDAV,
ECalBackendCalDAVPrivate);
+
+ g_mutex_init (&cbdav->priv->webdav_lock);
}
static void
diff --git a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 3a97bc160..5f0e005c9 100644
--- a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -42,6 +42,7 @@ struct _ECalBackendGTasksPrivate {
GDataAuthorizer *authorizer;
GDataTasksService *service;
GDataTasksTasklist *tasklist;
+ GRecMutex conn_lock;
GHashTable *preloaded; /* gchar *uid ~> ECalComponent * */
gboolean bad_request_for_timed_query;
};
@@ -255,22 +256,26 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
}
static gboolean
-ecb_gtasks_is_authorized (ECalBackendGTasks *cbgtasks)
+ecb_gtasks_is_authorized_locked (ECalBackendGTasks *cbgtasks)
{
+ gboolean res;
+
g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cbgtasks), FALSE);
if (!cbgtasks->priv->service ||
!cbgtasks->priv->tasklist)
return FALSE;
- return gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service));
+ res = gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service));
+
+ return res;
}
static gboolean
-ecb_gtasks_request_authorization (ECalBackendGTasks *cbgtasks,
- const ENamedParameters *credentials,
- GCancellable *cancellable,
- GError **error)
+ecb_gtasks_request_authorization_locked (ECalBackendGTasks *cbgtasks,
+ const ENamedParameters *credentials,
+ GCancellable *cancellable,
+ GError **error)
{
/* Make sure we have the GDataService configured
* before requesting authorization. */
@@ -314,9 +319,9 @@ ecb_gtasks_request_authorization (ECalBackendGTasks *cbgtasks,
}
static gboolean
-ecb_gtasks_prepare_tasklist (ECalBackendGTasks *cbgtasks,
- GCancellable *cancellable,
- GError **error)
+ecb_gtasks_prepare_tasklist_locked (ECalBackendGTasks *cbgtasks,
+ GCancellable *cancellable,
+ GError **error)
{
ESourceResource *resource;
ESource *source;
@@ -432,14 +437,20 @@ ecb_gtasks_connect_sync (ECalMetaBackend *meta_backend,
*out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
- if (ecb_gtasks_is_authorized (cbgtasks))
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+ if (ecb_gtasks_is_authorized_locked (cbgtasks)) {
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
return TRUE;
+ }
- success = ecb_gtasks_request_authorization (cbgtasks, credentials, cancellable, &local_error);
+ success = ecb_gtasks_request_authorization_locked (cbgtasks, credentials, cancellable, &local_error);
if (success)
success = gdata_authorizer_refresh_authorization (cbgtasks->priv->authorizer, cancellable,
&local_error);
if (success)
- success = ecb_gtasks_prepare_tasklist (cbgtasks, cancellable, &local_error);
+ success = ecb_gtasks_prepare_tasklist_locked (cbgtasks, cancellable, &local_error);
+
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
if (!success) {
if (g_error_matches (local_error, GDATA_SERVICE_ERROR,
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
@@ -469,20 +480,24 @@ ecb_gtasks_disconnect_sync (ECalMetaBackend *meta_backend,
cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
g_clear_object (&cbgtasks->priv->service);
g_clear_object (&cbgtasks->priv->authorizer);
g_clear_object (&cbgtasks->priv->tasklist);
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
return TRUE;
}
static gboolean
-ecb_gtasks_check_tasklist_changed_sync (ECalBackendGTasks *cbgtasks,
- const gchar *last_sync_tag,
- gboolean *out_changed,
- gint64 *out_taskslist_time,
- GCancellable *cancellable,
- GError **error)
+ecb_gtasks_check_tasklist_changed_locked_sync (ECalBackendGTasks *cbgtasks,
+ const gchar *last_sync_tag,
+ gboolean *out_changed,
+ gint64 *out_taskslist_time,
+ GCancellable *cancellable,
+ GError **error)
{
GDataFeed *feed;
gchar *id = NULL;
@@ -575,11 +590,17 @@ ecb_gtasks_get_changes_sync (ECalMetaBackend *meta_backend,
*out_modified_objects = NULL;
*out_removed_objects = NULL;
- if (!ecb_gtasks_check_tasklist_changed_sync (cbgtasks, last_sync_tag, &changed, &taskslist_time,
cancellable, error))
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+ if (!ecb_gtasks_check_tasklist_changed_locked_sync (cbgtasks, last_sync_tag, &changed,
&taskslist_time, cancellable, error)) {
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
return FALSE;
+ }
- if (!changed)
+ if (!changed) {
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
return TRUE;
+ }
cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
@@ -704,6 +725,7 @@ ecb_gtasks_get_changes_sync (ECalMetaBackend *meta_backend,
#endif
}
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
g_clear_object (&tasks_query);
g_clear_object (&feed);
@@ -825,11 +847,15 @@ ecb_gtasks_save_component_sync (ECalMetaBackend *meta_backend,
return FALSE;
}
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
if (overwrite_existing)
new_task = gdata_tasks_service_update_task (cbgtasks->priv->service, comp_task, cancellable,
error);
else
new_task = gdata_tasks_service_insert_task (cbgtasks->priv->service, comp_task,
cbgtasks->priv->tasklist, cancellable, error);
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
g_object_unref (comp_task);
if (!new_task)
@@ -896,10 +922,13 @@ ecb_gtasks_remove_component_sync (ECalMetaBackend *meta_backend,
return FALSE;
}
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
/* Ignore protocol errors here, libgdata 0.15.1 results with "Error code 204 when deleting an entry:
No Content",
while the delete succeeded */
if (!gdata_tasks_service_delete_task (cbgtasks->priv->service, task, cancellable, &local_error) &&
!g_error_matches (local_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR)) {
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
g_object_unref (cached_comp);
g_object_unref (task);
g_propagate_error (error, local_error);
@@ -909,6 +938,7 @@ ecb_gtasks_remove_component_sync (ECalMetaBackend *meta_backend,
g_clear_error (&local_error);
}
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
g_object_unref (cached_comp);
g_object_unref (task);
@@ -927,8 +957,13 @@ ecb_gtasks_requires_reconnect (ECalMetaBackend *meta_backend)
g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- if (!cbgtasks->priv->tasklist)
+
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+ if (!cbgtasks->priv->tasklist) {
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
return TRUE;
+ }
source = e_backend_get_source (E_BACKEND (cbgtasks));
resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
@@ -937,6 +972,7 @@ ecb_gtasks_requires_reconnect (ECalMetaBackend *meta_backend)
changed = id && *id && g_strcmp0 (id, gdata_entry_get_id (GDATA_ENTRY (cbgtasks->priv->tasklist))) !=
0 &&
g_strcmp0 (GTASKS_DEFAULT_TASKLIST_NAME, gdata_entry_get_id (GDATA_ENTRY
(cbgtasks->priv->tasklist))) != 0;
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
g_free (id);
return changed;
@@ -969,6 +1005,8 @@ e_cal_backend_gtasks_init (ECalBackendGTasks *cbgtasks)
cbgtasks->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbgtasks, E_TYPE_CAL_BACKEND_GTASKS,
ECalBackendGTasksPrivate);
cbgtasks->priv->preloaded = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
cbgtasks->priv->bad_request_for_timed_query = FALSE;
+
+ g_rec_mutex_init (&cbgtasks->priv->conn_lock);
}
static void
@@ -996,10 +1034,14 @@ ecb_gtasks_dispose (GObject *object)
{
ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
+ g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
g_clear_object (&cbgtasks->priv->service);
g_clear_object (&cbgtasks->priv->authorizer);
g_clear_object (&cbgtasks->priv->tasklist);
+ g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
g_hash_table_destroy (cbgtasks->priv->preloaded);
cbgtasks->priv->preloaded = NULL;
@@ -1007,6 +1049,17 @@ ecb_gtasks_dispose (GObject *object)
G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->dispose (object);
}
+static void
+ecb_gtasks_finalize (GObject *object)
+{
+ ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
+
+ g_rec_mutex_clear (&cbgtasks->priv->conn_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->finalize (object);
+}
+
static void
e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *klass)
{
@@ -1031,4 +1084,5 @@ e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *klass)
object_class = G_OBJECT_CLASS (klass);
object_class->constructed = ecb_gtasks_constructed;
object_class->dispose = ecb_gtasks_dispose;
+ object_class->finalize = ecb_gtasks_finalize;
}
diff --git a/src/calendar/backends/http/e-cal-backend-http.c b/src/calendar/backends/http/e-cal-backend-http.c
index cbeb2d87c..8ede6054d 100644
--- a/src/calendar/backends/http/e-cal-backend-http.c
+++ b/src/calendar/backends/http/e-cal-backend-http.c
@@ -39,6 +39,7 @@ struct _ECalBackendHttpPrivate {
SoupRequestHTTP *request;
GInputStream *input_stream;
+ GRecMutex conn_lock;
GHashTable *components; /* gchar *uid ~> icalcomponent * */
};
@@ -119,8 +120,12 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
- if (cbhttp->priv->request && cbhttp->priv->input_stream)
+ g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
+ if (cbhttp->priv->request && cbhttp->priv->input_stream) {
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
return TRUE;
+ }
source = e_backend_get_source (E_BACKEND (meta_backend));
@@ -130,6 +135,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
uri = ecb_http_dup_uri (cbhttp);
if (!uri || !*uri) {
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
g_free (uri);
g_propagate_error (error, EDC_ERROR_EX (OtherError, _("URI not set")));
@@ -214,6 +220,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
g_clear_object (&input_stream);
}
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
g_clear_error (&local_error);
g_free (uri);
@@ -232,6 +239,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
+ g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
g_clear_object (&cbhttp->priv->input_stream);
g_clear_object (&cbhttp->priv->request);
@@ -243,6 +252,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
cbhttp->priv->components = NULL;
}
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
source = e_backend_get_source (E_BACKEND (meta_backend));
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
@@ -305,7 +316,10 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
+ g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
if (!cbhttp->priv->request || !cbhttp->priv->input_stream) {
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
g_propagate_error (error, EDC_ERROR (RepositoryOffline));
return FALSE;
}
@@ -318,6 +332,7 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
if (new_etag && !*new_etag) {
new_etag = NULL;
} else if (new_etag && g_strcmp0 (last_sync_tag, new_etag) == 0) {
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
/* Nothing changed */
g_object_unref (message);
@@ -334,6 +349,8 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
icalstring = ecb_http_read_stream_sync (cbhttp->priv->input_stream,
soup_request_get_content_length (SOUP_REQUEST (cbhttp->priv->request)), cancellable, error);
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
if (!icalstring) {
/* The error is already set */
e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
@@ -582,19 +599,21 @@ e_cal_backend_http_dispose (GObject *object)
cbhttp = E_CAL_BACKEND_HTTP (object);
+ g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
g_clear_object (&cbhttp->priv->request);
g_clear_object (&cbhttp->priv->input_stream);
- if (cbhttp->priv->session) {
+ if (cbhttp->priv->session)
soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
- g_clear_object (&cbhttp->priv->session);
- }
if (cbhttp->priv->components) {
g_hash_table_destroy (cbhttp->priv->components);
cbhttp->priv->components = NULL;
}
+ g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_http_parent_class)->dispose (object);
}
@@ -605,6 +624,7 @@ e_cal_backend_http_finalize (GObject *object)
ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (object);
g_clear_object (&cbhttp->priv->session);
+ g_rec_mutex_clear (&cbhttp->priv->conn_lock);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_http_parent_class)->finalize (object);
@@ -615,6 +635,8 @@ e_cal_backend_http_init (ECalBackendHttp *cbhttp)
{
cbhttp->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbhttp, E_TYPE_CAL_BACKEND_HTTP, ECalBackendHttpPrivate);
+ g_rec_mutex_init (&cbhttp->priv->conn_lock);
+
e_cal_backend_set_writable (E_CAL_BACKEND (cbhttp), FALSE);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]