Bug #688660 - Crash on webdav contact cache update
authorMilan Crha <mcrha@redhat.com>
Tue, 20 Nov 2012 15:35:41 +0000 (16:35 +0100)
committerMilan Crha <mcrha@redhat.com>
Tue, 20 Nov 2012 15:36:28 +0000 (16:36 +0100)
addressbook/backends/webdav/e-book-backend-webdav.c

index e414eb4..dcb7db9 100644 (file)
@@ -73,6 +73,8 @@ struct _EBookBackendWebdavPrivate {
        gchar              *password;
        gboolean supports_getctag;
 
+       GMutex cache_lock;
+       GMutex update_lock;
        EBookBackendCache *cache;
 };
 
@@ -388,7 +390,9 @@ e_book_backend_webdav_create_contacts (EBookBackend *backend,
                contact = new_contact;
        }
 
+       g_mutex_lock (&priv->cache_lock);
        e_book_backend_cache_add_contact (priv->cache, contact);
+       g_mutex_unlock (&priv->cache_lock);
 
        added_contacts.data = contact;
        e_data_book_respond_create_contacts (book, opid, EDB_ERROR (SUCCESS), &added_contacts);
@@ -462,7 +466,9 @@ e_book_backend_webdav_remove_contacts (EBookBackend *backend,
                return;
        }
 
+       g_mutex_lock (&priv->cache_lock);
        e_book_backend_cache_remove_contact (priv->cache, uid);
+       g_mutex_unlock (&priv->cache_lock);
 
        deleted_ids.data = uid;
        e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (SUCCESS), &deleted_ids);
@@ -539,6 +545,7 @@ e_book_backend_webdav_modify_contacts (EBookBackend *backend,
        g_free (status_reason);
 
        uid = e_contact_get_const (contact, E_CONTACT_UID);
+       g_mutex_lock (&priv->cache_lock);
        e_book_backend_cache_remove_contact (priv->cache, uid);
 
        etag = e_contact_get_const (contact, E_CONTACT_REV);
@@ -554,6 +561,7 @@ e_book_backend_webdav_modify_contacts (EBookBackend *backend,
                }
        }
        e_book_backend_cache_add_contact (priv->cache, contact);
+       g_mutex_unlock (&priv->cache_lock);
 
        modified_contacts.data = contact;
        e_data_book_respond_modify_contacts (book, opid, EDB_ERROR (SUCCESS), &modified_contacts);
@@ -574,13 +582,17 @@ e_book_backend_webdav_get_contact (EBookBackend *backend,
        gchar                      *vcard;
 
        if (!e_backend_get_online (E_BACKEND (backend))) {
+               g_mutex_lock (&priv->cache_lock);
                contact = e_book_backend_cache_get_contact (priv->cache, uid);
+               g_mutex_unlock (&priv->cache_lock);
        } else {
                contact = download_contact (webdav, uid);
                /* update cache as we possibly have changes */
                if (contact != NULL) {
+                       g_mutex_lock (&priv->cache_lock);
                        e_book_backend_cache_remove_contact (priv->cache, uid);
                        e_book_backend_cache_add_contact (priv->cache, contact);
+                       g_mutex_unlock (&priv->cache_lock);
                }
        }
 
@@ -883,9 +895,11 @@ check_addressbook_changed (EBookBackendWebdav *webdav,
                                        if (*new_ctag) {
                                                const gchar *my_ctag;
 
+                                               g_mutex_lock (&priv->cache_lock);
                                                my_ctag = e_file_cache_get_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY);
                                                res = !my_ctag || !g_str_equal (my_ctag, *new_ctag);
                                                priv->supports_getctag = TRUE;
+                                               g_mutex_unlock (&priv->cache_lock);
                                        }
                                }
 
@@ -919,8 +933,11 @@ download_contacts (EBookBackendWebdav *webdav,
        gint                        i;
        gchar                     *new_ctag = NULL;
 
+       g_mutex_lock (&priv->update_lock);
+
        if (!check_addressbook_changed (webdav, &new_ctag)) {
                g_free (new_ctag);
+               g_mutex_unlock (&priv->update_lock);
                return EDB_ERROR (SUCCESS);
        }
 
@@ -939,6 +956,7 @@ download_contacts (EBookBackendWebdav *webdav,
                g_free (new_ctag);
                if (book_view)
                        e_data_book_view_notify_progress (book_view, -1, NULL);
+               g_mutex_unlock (&priv->update_lock);
                return webdav_handle_auth_request (webdav);
        }
        if (status != 207) {
@@ -957,6 +975,8 @@ download_contacts (EBookBackendWebdav *webdav,
                if (book_view)
                        e_data_book_view_notify_progress (book_view, -1, NULL);
 
+               g_mutex_unlock (&priv->update_lock);
+
                return error;
        }
        if (message->response_body == NULL) {
@@ -967,6 +987,8 @@ download_contacts (EBookBackendWebdav *webdav,
                if (book_view)
                        e_data_book_view_notify_progress (book_view, -1, NULL);
 
+               g_mutex_unlock (&priv->update_lock);
+
                return e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, _("No response body in webdav PROPFIND result"));
        }
 
@@ -1021,15 +1043,20 @@ download_contacts (EBookBackendWebdav *webdav,
 
                etag = (const gchar *) element->etag;
 
+               g_mutex_lock (&priv->cache_lock);
                contact = e_book_backend_cache_get_contact (priv->cache, complete_uri);
+               g_mutex_unlock (&priv->cache_lock);
+
                /* download contact if it is not cached or its ETag changed */
                if (contact == NULL || etag == NULL ||
                    strcmp (e_contact_get_const (contact, E_CONTACT_REV), etag) != 0) {
                        contact = download_contact (webdav, complete_uri);
                        if (contact != NULL) {
+                               g_mutex_lock (&priv->cache_lock);
                                if (e_book_backend_cache_remove_contact (priv->cache, complete_uri))
                                        e_book_backend_notify_remove (book_backend, complete_uri);
                                e_book_backend_cache_add_contact (priv->cache, contact);
+                               g_mutex_unlock (&priv->cache_lock);
                                e_book_backend_notify_update (book_backend, contact);
                        }
                }
@@ -1050,14 +1077,18 @@ download_contacts (EBookBackendWebdav *webdav,
        g_object_unref (message);
 
        if (new_ctag) {
+               g_mutex_lock (&priv->cache_lock);
                if (!e_file_cache_replace_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag))
                        e_file_cache_add_object (E_FILE_CACHE (priv->cache), WEBDAV_CTAG_KEY, new_ctag);
+               g_mutex_unlock (&priv->cache_lock);
        }
        g_free (new_ctag);
 
        if (book_view)
                e_data_book_view_notify_progress (book_view, -1, NULL);
 
+       g_mutex_unlock (&priv->update_lock);
+
        return EDB_ERROR (SUCCESS);
 }
 
@@ -1099,7 +1130,9 @@ e_book_backend_webdav_start_view (EBookBackend *backend,
        sexp = e_data_book_view_get_sexp (book_view);
        query = e_book_backend_sexp_text (sexp);
 
+       g_mutex_lock (&priv->cache_lock);
        contacts = e_book_backend_cache_get_contacts (priv->cache, query);
+       g_mutex_unlock (&priv->cache_lock);
 
        for (l = contacts; l != NULL; l = g_list_next (l)) {
                EContact *contact = l->data;
@@ -1170,7 +1203,10 @@ e_book_backend_webdav_get_contact_list (EBookBackend *backend,
        }
 
        /* answer query from cache */
+       g_mutex_lock (&priv->cache_lock);
        contact_list = e_book_backend_cache_get_contacts (priv->cache, query);
+       g_mutex_unlock (&priv->cache_lock);
+
        vcard_list   = NULL;
        for (c = contact_list; c != NULL; c = g_list_next (c)) {
                EContact *contact = c->data;
@@ -1211,7 +1247,10 @@ e_book_backend_webdav_get_contact_list_uids (EBookBackend *backend,
        }
 
        /* answer query from cache */
+       g_mutex_lock (&priv->cache_lock);
        contact_list = e_book_backend_cache_get_contacts (priv->cache, query);
+       g_mutex_unlock (&priv->cache_lock);
+
        uids_list   = NULL;
        for (c = contact_list; c != NULL; c = g_list_next (c)) {
                EContact *contact = c->data;
@@ -1317,9 +1356,13 @@ e_book_backend_webdav_open (EBookBackend *backend,
                return;
        }
 
-       filename = g_build_filename (cache_dir, "cache.xml", NULL);
-       priv->cache = e_book_backend_cache_new (filename);
-       g_free (filename);
+       g_mutex_lock (&priv->cache_lock);
+       if (!priv->cache) {
+               filename = g_build_filename (cache_dir, "cache.xml", NULL);
+               priv->cache = e_book_backend_cache_new (filename);
+               g_free (filename);
+       }
+       g_mutex_unlock (&priv->cache_lock);
 
        session = soup_session_sync_new ();
        g_object_set (session, SOUP_SESSION_TIMEOUT, 90, NULL);
@@ -1430,6 +1473,18 @@ e_book_backend_webdav_dispose (GObject *object)
        G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->dispose (object);
 }
 
+static void
+e_book_backend_webdav_finalize (GObject *object)
+{
+       EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (object);
+       EBookBackendWebdavPrivate *priv = webdav->priv;
+
+       g_mutex_clear (&priv->cache_lock);
+       g_mutex_clear (&priv->update_lock);
+
+       G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->finalize (object);
+}
+
 static ESourceAuthenticationResult
 book_backend_webdav_try_password_sync (ESourceAuthenticator *authenticator,
                                        const GString *password,
@@ -1507,6 +1562,7 @@ e_book_backend_webdav_class_init (EBookBackendWebdavClass *class)
        backend_class->stop_view                = e_book_backend_webdav_stop_view;
 
        object_class->dispose                   = e_book_backend_webdav_dispose;
+       object_class->finalize                  = e_book_backend_webdav_finalize;
 }
 
 static void
@@ -1520,6 +1576,9 @@ e_book_backend_webdav_init (EBookBackendWebdav *backend)
 {
        backend->priv = E_BOOK_BACKEND_WEBDAV_GET_PRIVATE (backend);
 
+       g_mutex_init (&backend->priv->cache_lock);
+       g_mutex_init (&backend->priv->update_lock);
+
        g_signal_connect (
                backend, "notify::online",
                G_CALLBACK (e_book_backend_webdav_notify_online_cb), NULL);