[evolution-data-server/gnome-3-8] Make CamelPOP3Store a bit more thread-safe.



commit 590dc3968326d63494627020d2139c82fcf5510b
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon May 20 17:43:46 2013 -0400

    Make CamelPOP3Store a bit more thread-safe.
    
    * Make CamelPOP3Store's cache and engine members private.
    
    * Guard the private cache and engine members with a mutex.
    
    * Add thread-safe accessors which return a new reference:
    
        camel_pop3_store_ref_cache()
        camel_pop3_store_ref_engine()
    
    TODO: CamelPOP3Engine itself should also be made thread-safe, but that
          will be considerably more work.  This commit merely prevents the
          CamelPOP3Engine from being finalized while still in use.
    
    (cherry picked from commit 0338a31f78160beadaba421698c79635737c6b8c)

 camel/providers/pop3/camel-pop3-folder.c |  154 +++++++++++++-------
 camel/providers/pop3/camel-pop3-store.c  |  239 +++++++++++++++++++++++-------
 camel/providers/pop3/camel-pop3-store.h  |    7 +-
 3 files changed, 287 insertions(+), 113 deletions(-)
---
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index 5e6f438..96d45fa 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -41,19 +41,26 @@
 G_DEFINE_TYPE (CamelPOP3Folder, camel_pop3_folder, CAMEL_TYPE_FOLDER)
 
 static void
-free_fi (CamelPOP3Folder *pop3_folder,CamelPOP3FolderInfo *fi)
+free_fi (CamelPOP3Folder *pop3_folder,
+         CamelPOP3FolderInfo *fi)
 {
 
        CamelPOP3Store *pop3_store;
        CamelStore *store;
 
-       store = camel_folder_get_parent_store ((CamelFolder *) pop3_folder);
+       store = camel_folder_get_parent_store (CAMEL_FOLDER (pop3_folder));
        pop3_store = CAMEL_POP3_STORE (store);
 
        g_hash_table_remove (pop3_folder->uids_id, GINT_TO_POINTER (fi->id));
-       if (fi->cmd) {
-               camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+       if (fi->cmd != NULL) {
+               CamelPOP3Engine *pop3_engine;
+
+               pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
+               camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                fi->cmd = NULL;
+
+               g_object_unref (pop3_engine);
        }
        g_free (fi->uid);
        g_free (fi);
@@ -155,7 +162,6 @@ cmd_list (CamelPOP3Engine *pe,
        guchar *line;
        CamelFolder *folder = data;
        CamelStore *parent_store;
-       CamelPOP3Store *pop3_store;
        CamelPOP3FolderInfo *fi;
        gint i = 0, total, last_uid=-1;
        CamelPOP3Folder *pop3_folder;
@@ -164,7 +170,6 @@ cmd_list (CamelPOP3Engine *pe,
        gint batch_fetch_count;
 
        parent_store = camel_folder_get_parent_store (folder);
-       pop3_store = CAMEL_POP3_STORE (parent_store);
        pop3_folder = (CamelPOP3Folder *) folder;
        service = (CamelService *) parent_store;
 
@@ -183,7 +188,7 @@ cmd_list (CamelPOP3Engine *pe,
                                fi->size = size;
                                fi->id = id;
                                fi->index = ((CamelPOP3Folder *) folder)->uids->len;
-                               if ((pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) == 0)
+                               if ((pe->capa & CAMEL_POP3_CAP_UIDL) == 0)
                                        fi->cmd = camel_pop3_engine_command_new (
                                                pe,
                                                CAMEL_POP3_COMMAND_MULTI,
@@ -384,9 +389,15 @@ pop3_folder_dispose (GObject *object)
 
                for (i = 0; i < pop3_folder->uids->len; i++, fi++) {
                        if (fi[0]->cmd && pop3_store && is_online) {
-                               while (camel_pop3_engine_iterate (pop3_store->engine, fi[0]->cmd, NULL, NULL) 
0)
+                               CamelPOP3Engine *pop3_engine;
+
+                               pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
+                               while (camel_pop3_engine_iterate (pop3_engine, fi[0]->cmd, NULL, NULL) > 0)
                                        ;
-                               camel_pop3_engine_command_free (pop3_store->engine, fi[0]->cmd);
+                               camel_pop3_engine_command_free (pop3_engine, fi[0]->cmd);
+
+                               g_clear_object (&pop3_engine);
                        }
 
                        g_free (fi[0]->uid);
@@ -438,7 +449,9 @@ pop3_folder_get_filename (CamelFolder *folder,
        CamelStore *parent_store;
        CamelPOP3Folder *pop3_folder;
        CamelPOP3Store *pop3_store;
+       CamelDataCache *pop3_cache;
        CamelPOP3FolderInfo *fi;
+       gchar *filename;
 
        parent_store = camel_folder_get_parent_store (folder);
 
@@ -454,8 +467,12 @@ pop3_folder_get_filename (CamelFolder *folder,
                return NULL;
        }
 
-       return camel_data_cache_get_filename (
-               pop3_store->cache, "cache", fi->uid);
+       pop3_cache = camel_pop3_store_ref_cache (pop3_store);
+       filename = camel_data_cache_get_filename (
+               pop3_cache, "cache", fi->uid);
+       g_clear_object (&pop3_cache);
+
+       return filename;
 }
 
 static gboolean
@@ -491,6 +508,8 @@ pop3_folder_get_message_sync (CamelFolder *folder,
        CamelMimeMessage *message = NULL;
        CamelPOP3Store *pop3_store;
        CamelPOP3Folder *pop3_folder;
+       CamelDataCache *pop3_cache;
+       CamelPOP3Engine *pop3_engine;
        CamelPOP3Command *pcr;
        CamelPOP3FolderInfo *fi;
        gchar buffer[1];
@@ -541,16 +560,19 @@ pop3_folder_get_message_sync (CamelFolder *folder,
        camel_operation_push_message (
                cancellable, _("Retrieving POP message %d"), fi->id);
 
+       pop3_cache = camel_pop3_store_ref_cache (pop3_store);
+       pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
        /* If we have an oustanding retrieve message running, wait for that to complete
         * & then retrieve from cache, otherwise, start a new one, and similar */
 
        if (fi->cmd != NULL) {
-               while ((i = camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, cancellable, error)) > 0)
+               while ((i = camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, error)) > 0)
                        ;
 
                /* getting error code? */
                /*g_assert (fi->cmd->state == CAMEL_POP3_COMMAND_DATA);*/
-               camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+               camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                fi->cmd = NULL;
 
                if (i == -1) {
@@ -561,20 +583,20 @@ pop3_folder_get_message_sync (CamelFolder *folder,
        }
 
        /* check to see if we have safely written flag set */
-       if (pop3_store->cache == NULL
-           || (stream = camel_data_cache_get (pop3_store->cache, "cache", fi->uid, NULL)) == NULL
+       if (pop3_cache == NULL
+           || (stream = camel_data_cache_get (pop3_cache, "cache", fi->uid, NULL)) == NULL
            || camel_stream_read (stream, buffer, 1, cancellable, NULL) != 1
            || buffer[0] != '#') {
 
                /* Initiate retrieval, if disk backing fails, use a memory backing */
-               if (pop3_store->cache == NULL
-                   || (stream = camel_data_cache_add (pop3_store->cache, "cache", fi->uid, NULL)) == NULL)
+               if (pop3_cache == NULL
+                   || (stream = camel_data_cache_add (pop3_cache, "cache", fi->uid, NULL)) == NULL)
                        stream = camel_stream_mem_new ();
 
                /* ref it, the cache storage routine unref's when done */
                fi->stream = g_object_ref (stream);
                pcr = camel_pop3_engine_command_new (
-                       pop3_store->engine,
+                       pop3_engine,
                        CAMEL_POP3_COMMAND_MULTI,
                        cmd_tocache, fi,
                        cancellable, error,
@@ -582,7 +604,7 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 
                /* Also initiate retrieval of some of the following
                 * messages, assume we'll be receiving them. */
-               if (auto_fetch && pop3_store->cache != NULL) {
+               if (auto_fetch && pop3_cache != NULL) {
                        /* This should keep track of the last one retrieved,
                         * also how many are still oustanding incase of random
                         * access on large folders. */
@@ -593,11 +615,11 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 
                                if (pfi->uid && pfi->cmd == NULL) {
                                        pfi->stream = camel_data_cache_add (
-                                               pop3_store->cache,
+                                               pop3_cache,
                                                "cache", pfi->uid, NULL);
                                        if (pfi->stream) {
                                                pfi->cmd = camel_pop3_engine_command_new (
-                                                       pop3_store->engine,
+                                                       pop3_engine,
                                                        CAMEL_POP3_COMMAND_MULTI,
                                                        cmd_tocache, pfi,
                                                        cancellable, error,
@@ -608,12 +630,12 @@ pop3_folder_get_message_sync (CamelFolder *folder,
                }
 
                /* now wait for the first one to finish */
-               while ((i = camel_pop3_engine_iterate (pop3_store->engine, pcr, cancellable, error)) > 0)
+               while ((i = camel_pop3_engine_iterate (pop3_engine, pcr, cancellable, error)) > 0)
                        ;
 
                /* getting error code? */
                /*g_assert (pcr->state == CAMEL_POP3_COMMAND_DATA);*/
-               camel_pop3_engine_command_free (pop3_store->engine, pcr);
+               camel_pop3_engine_command_free (pop3_engine, pcr);
                g_seekable_seek (
                        G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
 
@@ -649,6 +671,9 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 done:
        g_object_unref (stream);
 fail:
+       g_clear_object (&pop3_cache);
+       g_clear_object (&pop3_engine);
+
        camel_operation_pop_message (cancellable);
 
        return message;
@@ -662,6 +687,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
        CamelStore *parent_store;
        CamelPOP3Store *pop3_store;
        CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *) folder;
+       CamelPOP3Engine *pop3_engine;
        CamelPOP3Command *pcl, *pcu = NULL;
        gboolean success = TRUE;
        GError *local_error = NULL;
@@ -681,6 +707,8 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
        camel_operation_push_message (
                cancellable, _("Retrieving POP summary"));
 
+       pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
        /* Get rid of the old cache */
        if (pop3_folder->uids) {
                gint i;
@@ -698,7 +726,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
                for (i = 0; i < pop3_folder->uids->len; i++) {
                        CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
                        if (fi->cmd) {
-                               camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                               camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                                fi->cmd = NULL;
                        }
                        g_free (fi->uid);
@@ -721,19 +749,19 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
        pop3_folder->uids_id = g_hash_table_new (NULL, NULL);
 
        pcl = camel_pop3_engine_command_new (
-               pop3_store->engine,
+               pop3_engine,
                CAMEL_POP3_COMMAND_MULTI,
                cmd_list, folder,
                cancellable, &local_error,
                "LIST\r\n");
-       if (!local_error && (pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) != 0)
+       if (!local_error && (pop3_engine->capa & CAMEL_POP3_CAP_UIDL) != 0)
                pcu = camel_pop3_engine_command_new (
-                       pop3_store->engine,
+                       pop3_engine,
                        CAMEL_POP3_COMMAND_MULTI,
                        cmd_uidl, folder,
                        cancellable, &local_error,
                        "UIDL\r\n");
-       while ((i = camel_pop3_engine_iterate (pop3_store->engine, NULL, cancellable, &local_error)) > 0)
+       while ((i = camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, &local_error)) > 0)
                ;
 
        if (local_error) {
@@ -757,7 +785,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
                                g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get 
POP summary: "));
                }
 
-               camel_pop3_engine_command_free (pop3_store->engine, pcl);
+               camel_pop3_engine_command_free (pop3_engine, pcl);
        }
 
        if (pcu) {
@@ -770,7 +798,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
                                g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get 
POP summary: "));
                }
 
-               camel_pop3_engine_command_free (pop3_store->engine, pcu);
+               camel_pop3_engine_command_free (pop3_engine, pcu);
        } else {
                for (i = 0; i < pop3_folder->uids->len; i++) {
                        CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
@@ -784,7 +812,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
                                                g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 
_("Cannot get POP summary: "));
                                }
 
-                               camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                               camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                                fi->cmd = NULL;
                        }
                        if (fi->uid) {
@@ -797,6 +825,8 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
        g_hash_table_destroy (pop3_folder->uids_id);
        pop3_folder->uids_id = NULL;
 
+       g_clear_object (&pop3_engine);
+
        camel_operation_pop_message (cancellable);
 
        return success;
@@ -860,6 +890,8 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
        CamelStore *parent_store;
        CamelPOP3Folder *pop3_folder;
        CamelPOP3Store *pop3_store;
+       CamelDataCache *pop3_cache;
+       CamelPOP3Engine *pop3_engine;
        CamelPOP3FolderInfo *fi;
        gint delete_after_days;
        gboolean delete_expunged;
@@ -910,26 +942,29 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
        camel_operation_push_message (
                cancellable, _("Expunging deleted messages"));
 
+       pop3_cache = camel_pop3_store_ref_cache (pop3_store);
+       pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
        for (i = 0; i < pop3_folder->uids->len; i++) {
                fi = pop3_folder->uids->pdata[i];
                /* busy already?  wait for that to finish first */
                if (fi->cmd) {
-                       while (camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, cancellable, NULL) > 0)
+                       while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
                                ;
-                       camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                       camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                        fi->cmd = NULL;
                }
 
                if (fi->flags & CAMEL_MESSAGE_DELETED) {
                        fi->cmd = camel_pop3_engine_command_new (
-                               pop3_store->engine,
+                               pop3_engine,
                                0, NULL, NULL,
                                cancellable, NULL,
                                "DELE %u\r\n", fi->id);
 
                        /* also remove from cache */
-                       if (pop3_store->cache && fi->uid)
-                               camel_data_cache_remove (pop3_store->cache, "cache", fi->uid, NULL);
+                       if (pop3_cache != NULL && fi->uid)
+                               camel_data_cache_remove (pop3_cache, "cache", fi->uid, NULL);
                }
        }
 
@@ -937,15 +972,18 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
                fi = pop3_folder->uids->pdata[i];
                /* wait for delete commands to finish */
                if (fi->cmd) {
-                       while (camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, cancellable, NULL) > 0)
+                       while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
                                ;
-                       camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                       camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                        fi->cmd = NULL;
                }
                camel_operation_progress (
                        cancellable, (i + 1) * 100 / pop3_folder->uids->len);
        }
 
+       g_clear_object (&pop3_cache);
+       g_clear_object (&pop3_engine);
+
        camel_operation_pop_message (cancellable);
 
        return camel_pop3_store_expunge (pop3_store, cancellable, error);
@@ -1039,6 +1077,7 @@ pop3_get_message_time_from_cache (CamelFolder *folder,
 {
        CamelStore *parent_store;
        CamelPOP3Store *pop3_store;
+       CamelDataCache *pop3_cache;
        CamelStream *stream = NULL;
        gchar buffer[1];
        gboolean res = FALSE;
@@ -1050,9 +1089,10 @@ pop3_get_message_time_from_cache (CamelFolder *folder,
        parent_store = camel_folder_get_parent_store (folder);
        pop3_store = CAMEL_POP3_STORE (parent_store);
 
-       g_return_val_if_fail (pop3_store->cache != NULL, FALSE);
+       pop3_cache = camel_pop3_store_ref_cache (pop3_store);
+       g_return_val_if_fail (pop3_cache != NULL, FALSE);
 
-       if ((stream = camel_data_cache_get (pop3_store->cache, "cache", uid, NULL)) != NULL
+       if ((stream = camel_data_cache_get (pop3_cache, "cache", uid, NULL)) != NULL
            && camel_stream_read (stream, buffer, 1, NULL, NULL) == 1
            && buffer[0] == '#') {
                CamelMimeMessage *message;
@@ -1077,9 +1117,9 @@ pop3_get_message_time_from_cache (CamelFolder *folder,
                }
        }
 
-       if (stream) {
-               g_object_unref (stream);
-       }
+       g_clear_object (&stream);
+       g_clear_object (&pop3_cache);
+
        return res;
 }
 
@@ -1092,10 +1132,12 @@ camel_pop3_delete_old (CamelFolder *folder,
        CamelStore *parent_store;
        CamelPOP3Folder *pop3_folder;
        CamelPOP3FolderInfo *fi;
-       gint i;
+       CamelPOP3Engine *pop3_engine;
        CamelPOP3Store *pop3_store;
+       CamelDataCache *pop3_cache;
        CamelMimeMessage *message;
        time_t temp, message_time;
+       gint i;
 
        parent_store = camel_folder_get_parent_store (folder);
 
@@ -1109,6 +1151,9 @@ camel_pop3_delete_old (CamelFolder *folder,
 
        pop3_folder = CAMEL_POP3_FOLDER (folder);
        pop3_store = CAMEL_POP3_STORE (parent_store);
+       pop3_cache = camel_pop3_store_ref_cache (pop3_store);
+       pop3_engine = camel_pop3_store_ref_engine (pop3_store);
+
        temp = time (&temp);
 
        d (printf ("%s(%d): pop3_folder->uids->len=[%d]\n", __FILE__, __LINE__, pop3_folder->uids->len));
@@ -1117,11 +1162,11 @@ camel_pop3_delete_old (CamelFolder *folder,
                fi = pop3_folder->uids->pdata[i];
 
                if (fi->cmd) {
-                       while (camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, cancellable, NULL) > 
0) {
+                       while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0) {
                                ; /* do nothing - iterating until end */
                        }
 
-                       camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                       camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                        fi->cmd = NULL;
                }
 
@@ -1153,24 +1198,24 @@ camel_pop3_delete_old (CamelFolder *folder,
 
                        if (day_lag > days_to_delete) {
                                if (fi->cmd) {
-                                       while (camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, 
cancellable, NULL) > 0) {
+                                       while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, 
NULL) > 0) {
                                                ; /* do nothing - iterating until end */
                                        }
 
-                                       camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                                       camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                                        fi->cmd = NULL;
                                }
                                d (printf (
                                        "%s(%d): Deleting old messages\n",
                                        __FILE__, __LINE__));
                                fi->cmd = camel_pop3_engine_command_new (
-                                       pop3_store->engine,
+                                       pop3_engine,
                                        0, NULL, NULL,
                                        cancellable, NULL,
                                        "DELE %u\r\n", fi->id);
                                /* also remove from cache */
-                               if (pop3_store->cache && fi->uid) {
-                                       camel_data_cache_remove (pop3_store->cache, "cache", fi->uid, NULL);
+                               if (pop3_cache != NULL && fi->uid) {
+                                       camel_data_cache_remove (pop3_cache, "cache", fi->uid, NULL);
                                }
                        }
                }
@@ -1180,14 +1225,17 @@ camel_pop3_delete_old (CamelFolder *folder,
                fi = pop3_folder->uids->pdata[i];
                /* wait for delete commands to finish */
                if (fi->cmd) {
-                       while (camel_pop3_engine_iterate (pop3_store->engine, fi->cmd, cancellable, NULL) > 0)
+                       while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
                                ;
-                       camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+                       camel_pop3_engine_command_free (pop3_engine, fi->cmd);
                        fi->cmd = NULL;
                }
                camel_operation_progress (
                        cancellable, (i + 1) * 100 / pop3_folder->uids->len);
        }
 
+       g_clear_object (&pop3_cache);
+       g_clear_object (&pop3_engine);
+
        return camel_pop3_store_expunge (pop3_store, cancellable, error);
 }
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index 92574f8..8890c47 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -45,6 +45,10 @@
 #include <ws2tcpip.h>
 #endif
 
+#define CAMEL_POP3_STORE_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_POP3_STORE, CamelPOP3StorePrivate))
+
 /* Specified in RFC 1939 */
 #define POP3_PORT  110
 #define POP3S_PORT 995
@@ -52,6 +56,12 @@
 /* defines the length of the server error message we can display in the error dialog */
 #define POP3_ERROR_SIZE_LIMIT 60
 
+struct _CamelPOP3StorePrivate {
+       GMutex property_lock;
+       CamelDataCache *cache;
+       CamelPOP3Engine *engine;
+};
+
 enum {
        PROP_0,
        PROP_CONNECTABLE,
@@ -102,6 +112,7 @@ connect_to_server (CamelService *service,
        CamelNetworkSecurityMethod method;
        CamelSettings *settings;
        CamelStream *tcp_stream;
+       CamelPOP3Engine *pop3_engine = NULL;
        CamelPOP3Command *pc;
        gboolean disable_extensions;
        gboolean success = TRUE;
@@ -140,7 +151,7 @@ connect_to_server (CamelService *service,
        if (disable_extensions)
                flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
 
-       if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags, cancellable, &local_error)) ||
+       if (!(pop3_engine = camel_pop3_engine_new (tcp_stream, flags, cancellable, &local_error)) ||
            local_error != NULL) {
                if (local_error)
                        g_propagate_error (error, local_error);
@@ -159,7 +170,7 @@ connect_to_server (CamelService *service,
                goto exit;
        }
 
-       if (!(store->engine->capa & CAMEL_POP3_CAP_STLS)) {
+       if (!(pop3_engine->capa & CAMEL_POP3_CAP_STLS)) {
                g_set_error (
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                        _("Failed to connect to POP server %s in secure mode: %s"),
@@ -168,18 +179,18 @@ connect_to_server (CamelService *service,
        }
 
        pc = camel_pop3_engine_command_new (
-               store->engine, 0, NULL, NULL,
+               pop3_engine, 0, NULL, NULL,
                cancellable, error, "STLS\r\n");
-       while (camel_pop3_engine_iterate (store->engine, NULL, cancellable, NULL) > 0)
+       while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
                ;
 
        ret = pc->state == CAMEL_POP3_COMMAND_OK;
-       camel_pop3_engine_command_free (store->engine, pc);
+       camel_pop3_engine_command_free (pop3_engine, pc);
 
        if (ret == FALSE) {
                gchar *tmp;
 
-               tmp = get_valid_utf8_error ((gchar *) store->engine->line);
+               tmp = get_valid_utf8_error ((gchar *) pop3_engine->line);
                g_set_error (
                        error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
                        /* Translators: Last %s is an optional
@@ -206,7 +217,7 @@ connect_to_server (CamelService *service,
 
        /* rfc2595, section 4 states that after a successful STLS
         * command, the client MUST discard prior CAPA responses */
-       if (!camel_pop3_engine_reget_capabilities (store->engine, cancellable, error))
+       if (!camel_pop3_engine_reget_capabilities (pop3_engine, cancellable, error))
                goto exception;
 
        goto exit;
@@ -217,23 +228,30 @@ stls_exception:
        /* if (clean_quit) {
                / * try to disconnect cleanly * /
                pc = camel_pop3_engine_command_new (
-                       store->engine, 0, NULL, NULL,
+                       pop3_engine, 0, NULL, NULL,
                        cancellable, NULL, "QUIT\r\n");
-               while (camel_pop3_engine_iterate (store->engine, NULL, cancellable, NULL) > 0)
+               while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
                        ;
-               camel_pop3_engine_command_free (store->engine, pc);
+               camel_pop3_engine_command_free (pop3_engine, pc);
        }*/
 
- exception:
-       g_object_unref (store->engine);
+exception:
        g_object_unref (tcp_stream);
-       store->engine = NULL;
+
+       g_clear_object (&pop3_engine);
 
        success = FALSE;
 
 exit:
        g_free (host);
 
+       g_mutex_lock (&store->priv->property_lock);
+       if (pop3_engine != NULL)
+               store->priv->engine = g_object_ref (pop3_engine);
+       g_mutex_unlock (&store->priv->property_lock);
+
+       g_clear_object (&pop3_engine);
+
        return success;
 }
 
@@ -243,7 +261,8 @@ try_sasl (CamelPOP3Store *store,
           GCancellable *cancellable,
           GError **error)
 {
-       CamelPOP3Stream *stream = store->engine->stream;
+       CamelPOP3Engine *pop3_engine;
+       CamelPOP3Stream *pop3_stream;
        CamelNetworkSettings *network_settings;
        CamelAuthenticationResult result;
        CamelSettings *settings;
@@ -264,6 +283,9 @@ try_sasl (CamelPOP3Store *store,
 
        g_object_unref (settings);
 
+       pop3_engine = camel_pop3_store_ref_engine (store);
+       pop3_stream = pop3_engine->stream;
+
        sasl = camel_sasl_new ("pop", mechanism, service);
        if (sasl == NULL) {
                g_set_error (
@@ -276,14 +298,14 @@ try_sasl (CamelPOP3Store *store,
 
        string = g_strdup_printf ("AUTH %s\r\n", mechanism);
        ret = camel_stream_write_string (
-               CAMEL_STREAM (stream), string, cancellable, error);
+               CAMEL_STREAM (pop3_stream), string, cancellable, error);
        g_free (string);
 
        if (ret == -1)
                goto ioerror;
 
        while (1) {
-               if (camel_pop3_stream_line (stream, &line, &len, cancellable, error) == -1)
+               if (camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, error) == -1)
                        goto ioerror;
 
                if (strncmp ((gchar *) line, "+OK", 3) == 0) {
@@ -303,8 +325,8 @@ try_sasl (CamelPOP3Store *store,
                    || camel_sasl_get_authenticated (sasl)
                    || (resp = (guchar *) camel_sasl_challenge_base64_sync (sasl, (const gchar *) line + 2, 
cancellable, NULL)) == NULL) {
                        camel_stream_write_string (
-                               CAMEL_STREAM (stream), "*\r\n", cancellable, NULL);
-                       camel_pop3_stream_line (stream, &line, &len, cancellable, NULL);
+                               CAMEL_STREAM (pop3_stream), "*\r\n", cancellable, NULL);
+                       camel_pop3_stream_line (pop3_stream, &line, &len, cancellable, NULL);
                        g_set_error (
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -316,7 +338,7 @@ try_sasl (CamelPOP3Store *store,
 
                string = g_strdup_printf ("%s\r\n", resp);
                ret = camel_stream_write_string (
-                       CAMEL_STREAM (stream), string, cancellable, error);
+                       CAMEL_STREAM (pop3_stream), string, cancellable, error);
                g_free (string);
 
                g_free (resp);
@@ -339,6 +361,8 @@ exit:
 
        g_free (host);
 
+       g_clear_object (&pop3_engine);
+
        return result;
 }
 
@@ -387,12 +411,17 @@ pop3_store_get_property (GObject *object,
 static void
 pop3_store_dispose (GObject *object)
 {
-       CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
+       CamelPOP3StorePrivate *priv;
+
+       priv = CAMEL_POP3_STORE_GET_PRIVATE (object);
 
        /* Force disconnect so we dont have it run
         * later, after we've cleaned up some stuff. */
        camel_service_disconnect_sync (
-               CAMEL_SERVICE (pop3_store), TRUE, NULL, NULL);
+               CAMEL_SERVICE (object), TRUE, NULL, NULL);
+
+       g_clear_object (&priv->cache);
+       g_clear_object (&priv->engine);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (camel_pop3_store_parent_class)->dispose (object);
@@ -401,12 +430,11 @@ pop3_store_dispose (GObject *object)
 static void
 pop3_store_finalize (GObject *object)
 {
-       CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
+       CamelPOP3StorePrivate *priv;
+
+       priv = CAMEL_POP3_STORE_GET_PRIVATE (object);
 
-       if (pop3_store->engine)
-               g_object_unref (pop3_store->engine);
-       if (pop3_store->cache)
-               g_object_unref (pop3_store->cache);
+       g_mutex_clear (&priv->property_lock);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_pop3_store_parent_class)->finalize (object);
@@ -449,6 +477,7 @@ pop3_store_connect_sync (CamelService *service,
                          GError **error)
 {
        CamelPOP3Store *store = (CamelPOP3Store *) service;
+       CamelPOP3Engine *pop3_engine;
        CamelSettings *settings;
        CamelSession *session;
        const gchar *user_data_dir;
@@ -474,16 +503,26 @@ pop3_store_connect_sync (CamelService *service,
                goto exit;
        }
 
-       if (store->cache == NULL) {
-               store->cache = camel_data_cache_new (user_data_dir, error);
-               if (store->cache) {
+       g_mutex_lock (&store->priv->property_lock);
+
+       if (store->priv->cache == NULL) {
+               CamelDataCache *cache;
+
+               cache = camel_data_cache_new (user_data_dir, error);
+               if (cache != NULL) {
                        /* Ensure cache will never expire, otherwise
                         * it causes redownload of messages. */
-                       camel_data_cache_set_expire_age (store->cache, -1);
-                       camel_data_cache_set_expire_access (store->cache, -1);
+                       camel_data_cache_set_expire_age (cache, -1);
+                       camel_data_cache_set_expire_access (cache, -1);
+
+                       store->priv->cache = g_object_ref (cache);
+
+                       g_object_unref (cache);
                }
        }
 
+       g_mutex_unlock (&store->priv->property_lock);
+
        success = connect_to_server (service, cancellable, error);
 
        if (!success)
@@ -500,9 +539,11 @@ pop3_store_connect_sync (CamelService *service,
 
        /* Now that we are in the TRANSACTION state,
         * try regetting the capabilities */
-       store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
-       if (!camel_pop3_engine_reget_capabilities (store->engine, cancellable, error))
+       pop3_engine = camel_pop3_store_ref_engine (store);
+       pop3_engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
+       if (!camel_pop3_engine_reget_capabilities (pop3_engine, cancellable, error))
                success = FALSE;
+       g_clear_object (&pop3_engine);
 
 exit:
        g_free (mechanism);
@@ -523,14 +564,19 @@ pop3_store_disconnect_sync (CamelService *service,
        gboolean success;
 
        if (clean) {
+               CamelPOP3Engine *pop3_engine;
                CamelPOP3Command *pc;
 
+               pop3_engine = camel_pop3_store_ref_engine (store);
+
                pc = camel_pop3_engine_command_new (
-                       store->engine, 0, NULL, NULL,
+                       pop3_engine, 0, NULL, NULL,
                        cancellable, error, "QUIT\r\n");
-               while (camel_pop3_engine_iterate (store->engine, NULL, cancellable, NULL) > 0)
+               while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
                        ;
-               camel_pop3_engine_command_free (store->engine, pc);
+               camel_pop3_engine_command_free (pop3_engine, pc);
+
+               g_clear_object (&pop3_engine);
        }
 
        /* Chain up to parent's disconnect() method. */
@@ -538,8 +584,9 @@ pop3_store_disconnect_sync (CamelService *service,
 
        success = service_class->disconnect_sync (service, clean, cancellable, error);
 
-       g_object_unref (store->engine);
-       store->engine = NULL;
+       g_mutex_lock (&store->priv->property_lock);
+       g_clear_object (&store->priv->engine);
+       g_mutex_unlock (&store->priv->property_lock);
 
        return success;
 }
@@ -556,6 +603,7 @@ pop3_store_authenticate_sync (CamelService *service,
        CamelSettings *settings;
        CamelPOP3Command *pcu = NULL;
        CamelPOP3Command *pcp = NULL;
+       CamelPOP3Engine *pop3_engine;
        const gchar *password;
        gchar *host;
        gchar *user;
@@ -571,6 +619,8 @@ pop3_store_authenticate_sync (CamelService *service,
 
        g_object_unref (settings);
 
+       pop3_engine = camel_pop3_store_ref_engine (store);
+
        if (mechanism == NULL) {
                if (password == NULL) {
                        g_set_error_literal (
@@ -583,13 +633,13 @@ pop3_store_authenticate_sync (CamelService *service,
 
                /* pop engine will take care of pipelining ability */
                pcu = camel_pop3_engine_command_new (
-                       store->engine, 0, NULL, NULL, cancellable, error,
+                       pop3_engine, 0, NULL, NULL, cancellable, error,
                        "USER %s\r\n", user);
                pcp = camel_pop3_engine_command_new (
-                       store->engine, 0, NULL, NULL, cancellable, error,
+                       pop3_engine, 0, NULL, NULL, cancellable, error,
                        "PASS %s\r\n", password);
 
-       } else if (strcmp (mechanism, "+APOP") == 0 && store->engine->apop) {
+       } else if (strcmp (mechanism, "+APOP") == 0 && pop3_engine->apop) {
                gchar *secret, *md5asc, *d;
 
                if (password == NULL) {
@@ -601,7 +651,7 @@ pop3_store_authenticate_sync (CamelService *service,
                        goto exit;
                }
 
-               d = store->engine->apop;
+               d = pop3_engine->apop;
 
                while (*d != '\0') {
                        if (!isascii ((gint) * d)) {
@@ -622,20 +672,20 @@ pop3_store_authenticate_sync (CamelService *service,
                }
 
                secret = g_alloca (
-                       strlen (store->engine->apop) +
+                       strlen (pop3_engine->apop) +
                        strlen (password) + 1);
-               sprintf (secret, "%s%s", store->engine->apop, password);
+               sprintf (secret, "%s%s", pop3_engine->apop, password);
                md5asc = g_compute_checksum_for_string (
                        G_CHECKSUM_MD5, secret, -1);
                pcp = camel_pop3_engine_command_new (
-                       store->engine, 0, NULL, NULL, cancellable, error,
+                       pop3_engine, 0, NULL, NULL, cancellable, error,
                        "APOP %s %s\r\n", user, md5asc);
                g_free (md5asc);
 
        } else {
                GList *link;
 
-               link = store->engine->auth;
+               link = pop3_engine->auth;
                while (link != NULL) {
                        CamelServiceAuthType *auth = link->data;
 
@@ -656,7 +706,7 @@ pop3_store_authenticate_sync (CamelService *service,
                goto exit;
        }
 
-       while ((status = camel_pop3_engine_iterate (store->engine, pcp, cancellable, error)) > 0)
+       while ((status = camel_pop3_engine_iterate (pop3_engine, pcp, cancellable, error)) > 0)
                ;
 
        if (status == -1) {
@@ -671,7 +721,7 @@ pop3_store_authenticate_sync (CamelService *service,
 
                /* Abort authentication if the server rejects the user
                 * name.  Reprompting for a password won't do any good. */
-               tmp = get_valid_utf8_error ((gchar *) store->engine->line);
+               tmp = get_valid_utf8_error ((gchar *) pop3_engine->line);
                g_set_error (
                        error, CAMEL_SERVICE_ERROR,
                        CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -683,20 +733,23 @@ pop3_store_authenticate_sync (CamelService *service,
                g_free (tmp);
                result = CAMEL_AUTHENTICATION_ERROR;
 
-       } else if (pcp->state != CAMEL_POP3_COMMAND_OK)
+       } else if (pcp->state != CAMEL_POP3_COMMAND_OK) {
                result = CAMEL_AUTHENTICATION_REJECTED;
-       else
+       } else {
                result = CAMEL_AUTHENTICATION_ACCEPTED;
+       }
 
-       camel_pop3_engine_command_free (store->engine, pcp);
+       camel_pop3_engine_command_free (pop3_engine, pcp);
 
        if (pcu != NULL)
-               camel_pop3_engine_command_free (store->engine, pcu);
+               camel_pop3_engine_command_free (pop3_engine, pcu);
 
 exit:
        g_free (host);
        g_free (user);
 
+       g_clear_object (&pop3_engine);
+
        return result;
 }
 
@@ -721,8 +774,14 @@ pop3_store_query_auth_types_sync (CamelService *service,
        }
 
        if (connect_to_server (service, cancellable, error)) {
-               types = g_list_concat (types, g_list_copy (store->engine->auth));
+               CamelPOP3Engine *pop3_engine;
+
+               pop3_engine = camel_pop3_store_ref_engine (store);
+
+               types = g_list_concat (types, g_list_copy (pop3_engine->auth));
                pop3_store_disconnect_sync (service, TRUE, cancellable, NULL);
+
+               g_clear_object (&pop3_engine);
        }
 
        return types;
@@ -824,6 +883,8 @@ camel_pop3_store_class_init (CamelPOP3StoreClass *class)
        CamelServiceClass *service_class;
        CamelStoreClass *store_class;
 
+       g_type_class_add_private (class, sizeof (CamelPOP3StorePrivate));
+
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = pop3_store_set_property;
        object_class->get_property = pop3_store_get_property;
@@ -867,11 +928,70 @@ camel_network_service_init (CamelNetworkServiceInterface *interface)
 static void
 camel_pop3_store_init (CamelPOP3Store *pop3_store)
 {
+       pop3_store->priv = CAMEL_POP3_STORE_GET_PRIVATE (pop3_store);
+
+       g_mutex_init (&pop3_store->priv->property_lock);
+}
+
+/**
+ * camel_pop3_store_ref_cache:
+ * @store: a #CamelPOP3Store
+ *
+ * Returns the #CamelDataCache for @store.
+ *
+ * The returned #CamelDataCache is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelDataCache
+ **/
+CamelDataCache *
+camel_pop3_store_ref_cache (CamelPOP3Store *store)
+{
+       CamelDataCache *cache = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_POP3_STORE (store), NULL);
+
+       g_mutex_lock (&store->priv->property_lock);
+
+       if (store->priv->cache != NULL)
+               cache = g_object_ref (store->priv->cache);
+
+       g_mutex_unlock (&store->priv->property_lock);
+
+       return cache;
+}
+
+/**
+ * camel_pop3_store_ref_engine:
+ * @store: a #CamelPOP3Store
+ *
+ * Returns the #CamelPOP3Engine for @store.
+ *
+ * The returned #CamelPOP3Engine is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelPOP3Store
+ **/
+CamelPOP3Engine *
+camel_pop3_store_ref_engine (CamelPOP3Store *store)
+{
+       CamelPOP3Engine *engine = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_POP3_STORE (store), NULL);
+
+       g_mutex_lock (&store->priv->property_lock);
+
+       if (store->priv->engine != NULL)
+               engine = g_object_ref (store->priv->engine);
+
+       g_mutex_unlock (&store->priv->property_lock);
+
+       return engine;
 }
 
 /**
  * camel_pop3_store_expunge:
- * @store: the store
+ * @store: a #CamelPOP3Store
  * @error: return location for a #GError, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  *
@@ -885,6 +1005,7 @@ camel_pop3_store_expunge (CamelPOP3Store *store,
                           GError **error)
 {
        CamelPOP3Command *pc;
+       CamelPOP3Engine *pop3_engine;
        CamelServiceConnectionStatus status;
 
        status = camel_service_get_connection_status (CAMEL_SERVICE (store));
@@ -897,13 +1018,17 @@ camel_pop3_store_expunge (CamelPOP3Store *store,
                return FALSE;
        }
 
+       pop3_engine = camel_pop3_store_ref_engine (store);
+
        pc = camel_pop3_engine_command_new (
-               store->engine, 0, NULL, NULL, cancellable, error, "QUIT\r\n");
+               pop3_engine, 0, NULL, NULL, cancellable, error, "QUIT\r\n");
 
-       while (camel_pop3_engine_iterate (store->engine, NULL, cancellable, NULL) > 0)
+       while (camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, NULL) > 0)
                ;
 
-       camel_pop3_engine_command_free (store->engine, pc);
+       camel_pop3_engine_command_free (pop3_engine, pc);
+
+       g_clear_object (&pop3_engine);
 
        return TRUE;
 }
diff --git a/camel/providers/pop3/camel-pop3-store.h b/camel/providers/pop3/camel-pop3-store.h
index 77630a1..07776b6 100644
--- a/camel/providers/pop3/camel-pop3-store.h
+++ b/camel/providers/pop3/camel-pop3-store.h
@@ -58,9 +58,6 @@ typedef struct _CamelPOP3StorePrivate CamelPOP3StorePrivate;
 struct _CamelPOP3Store {
        CamelStore parent;
        CamelPOP3StorePrivate *priv;
-
-       CamelPOP3Engine *engine; /* pop processing engine */
-       CamelDataCache *cache;
 };
 
 struct _CamelPOP3StoreClass {
@@ -68,6 +65,10 @@ struct _CamelPOP3StoreClass {
 };
 
 GType          camel_pop3_store_get_type       (void);
+CamelDataCache *
+               camel_pop3_store_ref_cache      (CamelPOP3Store *store);
+CamelPOP3Engine *
+               camel_pop3_store_ref_engine     (CamelPOP3Store *store);
 gboolean       camel_pop3_store_expunge        (CamelPOP3Store *store,
                                                 GCancellable *cancellable,
                                                 GError **error);


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