diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c.imapx-empty-cache-file-temp-workaround evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c --- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c.imapx-empty-cache-file-temp-workaround 2014-06-16 15:00:03.000000000 +0200 +++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c 2015-05-26 15:02:30.395243456 +0200 @@ -182,6 +182,7 @@ camel_imapx_job_wait (CamelIMAPXJob *job { CamelIMAPXRealJob *real_job; GCancellable *cancellable; + gulong cancel_id = 0; gboolean success = TRUE; g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE); @@ -189,13 +190,23 @@ camel_imapx_job_wait (CamelIMAPXJob *job real_job = (CamelIMAPXRealJob *) job; cancellable = camel_imapx_job_get_cancellable (job); + if (G_IS_CANCELLABLE (cancellable)) + cancel_id = g_cancellable_connect ( + cancellable, + G_CALLBACK (imapx_job_cancelled_cb), + camel_imapx_job_ref (job), + (GDestroyNotify) camel_imapx_job_unref); + g_mutex_lock (&real_job->done_mutex); - while (!real_job->done_flag) + while (!real_job->done_flag && !g_cancellable_is_cancelled (cancellable)) g_cond_wait ( &real_job->done_cond, &real_job->done_mutex); g_mutex_unlock (&real_job->done_mutex); + if (cancel_id > 0) + g_cancellable_disconnect (cancellable, cancel_id); + /* Cancellation takes priority over other errors. */ if (g_cancellable_set_error_if_cancelled (cancellable, error)) { success = FALSE; @@ -233,7 +244,6 @@ camel_imapx_job_run (CamelIMAPXJob *job, GError **error) { GCancellable *cancellable; - gulong cancel_id = 0; gboolean success; g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE); @@ -245,21 +255,11 @@ camel_imapx_job_run (CamelIMAPXJob *job, if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - if (G_IS_CANCELLABLE (cancellable)) - cancel_id = g_cancellable_connect ( - cancellable, - G_CALLBACK (imapx_job_cancelled_cb), - camel_imapx_job_ref (job), - (GDestroyNotify) camel_imapx_job_unref); - success = job->start (job, is, cancellable, error); if (success && !job->noreply) success = camel_imapx_job_wait (job, error); - if (cancel_id > 0) - g_cancellable_disconnect (cancellable, cancel_id); - return success; } diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c.imapx-empty-cache-file-temp-workaround evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c --- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c.imapx-empty-cache-file-temp-workaround 2015-05-26 15:02:30.390243457 +0200 +++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c 2015-05-26 15:02:46.146242702 +0200 @@ -57,8 +57,8 @@ #define c(...) camel_imapx_debug(command, __VA_ARGS__) #define e(...) camel_imapx_debug(extra, __VA_ARGS__) -#define QUEUE_LOCK(x) (g_rec_mutex_lock(&(x)->queue_lock)) -#define QUEUE_UNLOCK(x) (g_rec_mutex_unlock(&(x)->queue_lock)) +#define QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->queue_lock) +#define QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->queue_lock) /* Try pipelining fetch requests, 'in bits' */ #define MULTI_SIZE (32768 * 8) @@ -5172,23 +5172,54 @@ imapx_command_fetch_message_done (CamelI g_free (tmp_filename); } - /* Delete the 'tmp' file only if the operation wasn't cancelled. It's because + /* Delete the 'tmp' file only if the operation succeeded. It's because cancelled operations end before they are properly finished (IMAP-protocol speaking), thus if any other GET_MESSAGE operation was waiting for this job, then it realized that the message was not downloaded and opened its own "tmp" file, but of the same name, thus this remove would drop file which could be used by a different GET_MESSAGE job. */ - if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (!local_error && !g_cancellable_is_cancelled (cancellable)) camel_data_cache_remove (data->message_cache, "tmp", data->uid, NULL); /* Avoid possible use-after-free when the imapx_unregister_job() can also free the 'job' structure. */ + camel_imapx_job_ref (job); + + imapx_unregister_job (is, job); + if (local_error != NULL) { - camel_imapx_job_take_error (job, local_error); - local_error = NULL; + CamelIMAPXJob *pending_job; + + /* Give a chance to other threads. */ + g_thread_yield (); + + pending_job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, data->uid); + if (pending_job != NULL) { + GIOStream *cache_stream; + + /* Wait for the job to finish. */ + camel_imapx_job_wait (pending_job, NULL); + camel_imapx_job_unref (pending_job); + + /* Disregard errors here. If we failed to retrieve the + * message from cache (implying the job we were waiting + * on failed or got cancelled), we'll just re-fetch it. */ + cache_stream = camel_data_cache_get (data->message_cache, "cur", data->uid, NULL); + if (cache_stream != NULL) { + g_clear_error (&local_error); + + g_clear_object (&data->stream); + data->stream = cache_stream; + } + } + + if (local_error) { + camel_imapx_job_take_error (job, local_error); + local_error = NULL; + } } - imapx_unregister_job (is, job); + camel_imapx_job_unref (job); exit: if (local_error != NULL) @@ -8344,9 +8375,7 @@ imapx_server_get_message (CamelIMAPXServ GetMessageData *data; gboolean registered; - job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid); - - if (job != NULL) { + while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid), job != NULL) { /* Promote the existing GET_MESSAGE * job's priority if ours is higher. */ if (pri > job->pri) @@ -8362,14 +8391,26 @@ imapx_server_get_message (CamelIMAPXServ cache_stream = camel_data_cache_get ( message_cache, "cur", message_uid, NULL); if (cache_stream != NULL) { - stream = camel_stream_new (cache_stream); + /* Return new file stream, instead of a DataCache's to not fight + on its content and position with other jobs, if any. */ + gchar *filename = camel_data_cache_get_filename (message_cache, "cur", message_uid); + stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL); + g_free (filename); g_object_unref (cache_stream); - return stream; + + if (stream) + return stream; } } QUEUE_LOCK (is); + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + QUEUE_UNLOCK (is); + + return NULL; + } + mi = camel_folder_summary_get (summary, message_uid); if (mi == NULL) { g_set_error ( diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h.imapx-empty-cache-file-temp-workaround evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c.imapx-empty-cache-file-temp-workaround evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c --- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c.imapx-empty-cache-file-temp-workaround 2014-12-02 16:07:54.000000000 +0100 +++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c 2015-05-26 15:02:46.148242702 +0200 @@ -704,7 +704,6 @@ imapx_store_finalize (GObject *object) priv = CAMEL_IMAPX_STORE_GET_PRIVATE (object); g_mutex_clear (&priv->get_finfo_lock); - g_mutex_clear (&priv->server_lock); g_hash_table_destroy (priv->quota_info); diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h.imapx-empty-cache-file-temp-workaround evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h