diff -up evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c
--- evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c.imapx-error-cancelled-message-download 2014-05-16 11:36:17.872612953 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c 2014-05-16 11:36:17.884612846 +0200
@@ -883,3 +883,21 @@ camel_imapx_conn_manager_close_connectio
g_list_free_full (connections, (GDestroyNotify) connection_info_cancel_and_unref);
}
+/* for debugging purposes only */
+void
+camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *con_man)
+{
+ GList *list, *link;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+ list = imapx_conn_manager_list_info (con_man);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *cinfo = link->data;
+ camel_imapx_server_dump_queue_status (cinfo->is);
+ connection_info_unref (cinfo);
+ }
+
+ g_list_free (list);
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h
--- evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h.imapx-error-cancelled-message-download 2014-05-16 11:36:17.873612944 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h 2014-05-16 11:36:17.884612846 +0200
@@ -84,6 +84,10 @@ void camel_imapx_conn_manager_update_co
CamelIMAPXServer *server,
const gchar *folder_name);
+/* for debugging purposes only */
+void camel_imapx_conn_manager_dump_queue_status
+ (CamelIMAPXConnManager *con_man);
+
G_END_DECLS
#endif /* _CAMEL_IMAPX_SERVER_H */
diff -up evolution-data-server-3.8.5/camel/camel-imapx-job.h.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-job.h
--- evolution-data-server-3.8.5/camel/camel-imapx-job.h.imapx-error-cancelled-message-download 2014-05-16 11:36:17.798613612 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-job.h 2014-05-16 11:36:17.884612846 +0200
@@ -55,7 +55,7 @@ struct _CamelIMAPXJob {
guint noreply:1; /* dont wait for reply */
guint32 type; /* operation type */
gint pri; /* the command priority */
- gshort commands; /* counts how many commands are outstanding */
+ volatile gint commands; /* counts how many commands are outstanding */
};
CamelIMAPXJob * camel_imapx_job_new (GCancellable *cancellable);
diff -up evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-server.c
--- evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-error-cancelled-message-download 2014-05-16 11:36:17.879612890 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-server.c 2014-05-16 11:36:17.885612837 +0200
@@ -989,9 +989,7 @@ imapx_uidset_add (struct _uidset_state *
/* Must hold QUEUE_LOCK */
static gboolean
imapx_command_start (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic,
- GCancellable *cancellable,
- GError **error)
+ CamelIMAPXCommand *ic)
{
CamelIMAPXStream *stream = NULL;
CamelIMAPXCommandPart *cp;
@@ -1002,6 +1000,7 @@ imapx_command_start (CamelIMAPXServer *i
gboolean success = FALSE;
gchar *string;
gint retval;
+ GCancellable *cancellable;
GError *local_error = NULL;
camel_imapx_command_close (ic);
@@ -1024,7 +1023,11 @@ imapx_command_start (CamelIMAPXServer *i
imapx_server_command_added (is, ic);
job = camel_imapx_command_get_job (ic);
- if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job), &local_error)) {
+ if (job)
+ cancellable = camel_imapx_job_get_cancellable (job);
+ else
+ cancellable = NULL;
+ if (job && g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
camel_imapx_job_set_error (job, local_error);
g_clear_error (&local_error);
goto err;
@@ -1034,7 +1037,7 @@ imapx_command_start (CamelIMAPXServer *i
if (stream == NULL) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ &local_error, CAMEL_IMAPX_ERROR, 1,
"Cannot issue command, no stream available");
goto err;
}
@@ -1052,7 +1055,7 @@ imapx_command_start (CamelIMAPXServer *i
string = g_strdup_printf (
"%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
retval = camel_stream_write_string (
- CAMEL_STREAM (stream), string, cancellable, error);
+ CAMEL_STREAM (stream), string, cancellable, &local_error);
g_free (string);
if (retval == -1)
@@ -1060,7 +1063,7 @@ imapx_command_start (CamelIMAPXServer *i
while (is->literal == ic && cp_literal_plus) {
/* Sent LITERAL+ continuation immediately */
- if (!imapx_continuation (is, stream, TRUE, cancellable, error))
+ if (!imapx_continuation (is, stream, TRUE, cancellable, &local_error))
goto err;
}
@@ -1080,6 +1083,10 @@ err:
if (ic->status->result == IMAPX_OK)
ic->status->result = IMAPX_UNKNOWN;
+ if (job && local_error) {
+ camel_imapx_job_set_error (job, local_error);
+ g_clear_error (&local_error);
+ }
/* Send a NULL GError since we've already set a
* GError to get here, and we're not interested
* in individual command errors. */
@@ -1134,9 +1141,7 @@ duplicate_fetch_or_refresh (CamelIMAPXSe
* must have QUEUE lock */
static gboolean
-imapx_command_start_next (CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+imapx_command_start_next (CamelIMAPXServer *is)
{
CamelIMAPXCommand *first_ic;
CamelFolder *folder;
@@ -1151,7 +1156,7 @@ imapx_command_start_next (CamelIMAPXServ
folder = g_weak_ref_get (&is->select_pending);
if (folder != NULL) {
- GQueue start = G_QUEUE_INIT;
+ CamelIMAPXCommand *start_ic = NULL;
GList *head, *link;
c (is->tagprefix, "-- Checking job queue for non-folder jobs\n");
@@ -1159,7 +1164,7 @@ imapx_command_start_next (CamelIMAPXServ
head = camel_imapx_command_queue_peek_head_link (is->queue);
/* Tag which commands in the queue to start. */
- for (link = head; link != NULL; link = g_list_next (link)) {
+ for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
CamelIMAPXCommand *ic = link->data;
if (ic->pri < min_pri)
@@ -1169,37 +1174,23 @@ imapx_command_start_next (CamelIMAPXServ
if (!ic->select) {
c (is->tagprefix, "--> starting '%s'\n", ic->name);
min_pri = ic->pri;
- g_queue_push_tail (&start, link);
- }
- if (g_queue_get_length (&start) == MAX_COMMANDS)
- break;
+ /* Each command must be removed from 'is->queue' before
+ * starting it, so we temporarily reference the command
+ * to avoid accidentally finalizing it. */
+ start_ic = camel_imapx_command_ref (ic);
+ }
}
- if (g_queue_is_empty (&start))
+ if (!start_ic)
c (is->tagprefix, "* no, waiting for pending select '%s'\n", camel_folder_get_full_name (folder));
- /* Start the tagged commands.
- *
- * Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- while ((link = g_queue_pop_head (&start)) != NULL) {
- CamelIMAPXCommand *ic;
-
- ic = camel_imapx_command_ref (link->data);
- camel_imapx_command_queue_delete_link (is->queue, link);
- imapx_server_command_removed (is, ic);
-
- success = imapx_command_start (
- is, ic, cancellable, error);
-
- camel_imapx_command_unref (ic);
-
- if (!success) {
- g_queue_clear (&start);
- break;
- }
+ /* Start the tagged command */
+ if (start_ic) {
+ camel_imapx_command_queue_remove (is->queue, start_ic);
+ imapx_server_command_removed (is, start_ic);
+ imapx_command_start (is, start_ic);
+ camel_imapx_command_unref (start_ic);
}
g_clear_object (&folder);
@@ -1219,7 +1210,7 @@ imapx_command_start_next (CamelIMAPXServ
if (stream != NULL) {
stop_result = imapx_stop_idle (
- is, stream, cancellable, error);
+ is, stream, is->cancellable, NULL);
g_object_unref (stream);
}
@@ -1255,9 +1246,8 @@ imapx_command_start_next (CamelIMAPXServ
/* See if any queued jobs on this select first */
folder = g_weak_ref_get (&is->select_folder);
if (folder != NULL) {
- GQueue start = G_QUEUE_INIT;
+ CamelIMAPXCommand *start_ic = NULL;
GList *head, *link;
- gboolean commands_started = FALSE;
c (
is->tagprefix, "- we're selected on '%s', current jobs?\n",
@@ -1284,7 +1274,7 @@ imapx_command_start_next (CamelIMAPXServ
head = camel_imapx_command_queue_peek_head_link (is->queue);
/* Tag which commands in the queue to start. */
- for (link = head; link != NULL; link = g_list_next (link)) {
+ for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
CamelIMAPXCommand *ic = link->data;
if (is->literal != NULL)
@@ -1299,48 +1289,29 @@ imapx_command_start_next (CamelIMAPXServ
!duplicate_fetch_or_refresh (is, ic))) {
c (is->tagprefix, "--> starting '%s'\n", ic->name);
min_pri = ic->pri;
- g_queue_push_tail (&start, link);
+ /* Each command must be removed from 'is->queue' before
+ * starting it, so we temporarily reference the command
+ * to avoid accidentally finalizing it. */
+ start_ic = camel_imapx_command_ref (ic);
} else {
/* This job isn't for the selected folder, but we don't want to
* consider jobs with _lower_ priority than this, even if they
* are for the selected folder. */
min_pri = ic->pri;
}
-
- if (g_queue_get_length (&start) == MAX_COMMANDS)
- break;
}
g_clear_object (&folder);
- /* Start the tagged commands.
- *
- * Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- while ((link = g_queue_pop_head (&start)) != NULL) {
- CamelIMAPXCommand *ic;
- gboolean success;
+ /* Start the tagged command */
+ if (start_ic) {
+ camel_imapx_command_queue_remove (is->queue, start_ic);
+ imapx_server_command_removed (is, start_ic);
+ imapx_command_start (is, start_ic);
+ camel_imapx_command_unref (start_ic);
- ic = camel_imapx_command_ref (link->data);
- camel_imapx_command_queue_delete_link (is->queue, link);
- imapx_server_command_removed (is, ic);
-
- success = imapx_command_start (
- is, ic, cancellable, error);
-
- camel_imapx_command_unref (ic);
-
- if (!success) {
- g_queue_clear (&start);
- return FALSE;
- }
-
- commands_started = TRUE;
- }
-
- if (commands_started)
return TRUE;
+ }
}
/* This won't be NULL because we checked for an empty queue above. */
@@ -1349,13 +1320,19 @@ imapx_command_start_next (CamelIMAPXServ
/* If we need to select a folder for the first command, do it now,
* once it is complete it will re-call us if it succeeded. */
if (first_ic->select) {
+ GError *local_error = NULL;
+ CamelIMAPXJob *job;
c (
is->tagprefix, "Selecting folder '%s' for command '%s'(%p)\n",
camel_folder_get_full_name (first_ic->select),
first_ic->name, first_ic);
- imapx_select (is, first_ic->select, FALSE, cancellable, error);
+ job = camel_imapx_command_get_job (first_ic);
+ imapx_select (is, first_ic->select, FALSE, job ? camel_imapx_job_get_cancellable (job) : NULL, &local_error);
+ if (local_error && job)
+ camel_imapx_job_set_error (job, local_error);
+ g_clear_error (&local_error);
} else {
- GQueue start = G_QUEUE_INIT;
+ CamelIMAPXCommand *start_ic = NULL;
GList *head, *link;
min_pri = first_ic->pri;
@@ -1365,7 +1342,7 @@ imapx_command_start_next (CamelIMAPXServ
head = camel_imapx_command_queue_peek_head_link (is->queue);
/* Tag which commands in the queue to start. */
- for (link = head; link != NULL; link = g_list_next (link)) {
+ for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
CamelIMAPXCommand *ic = link->data;
if (is->literal != NULL)
@@ -1378,37 +1355,21 @@ imapx_command_start_next (CamelIMAPXServ
!duplicate_fetch_or_refresh (is, ic))) {
c (is->tagprefix, "* queueing job %3d '%s'\n", (gint) ic->pri, ic->name);
min_pri = ic->pri;
- g_queue_push_tail (&start, link);
+ /* Each command must be removed from 'is->queue' before
+ * starting it, so we temporarily reference the command
+ * to avoid accidentally finalizing it. */
+ start_ic = camel_imapx_command_ref (ic);
}
-
- if (g_queue_get_length (&start) == MAX_COMMANDS)
- break;
}
g_clear_object (&folder);
- /* Start the tagged commands.
- *
- * Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- while ((link = g_queue_pop_head (&start)) != NULL) {
- CamelIMAPXCommand *ic;
- gboolean success;
-
- ic = camel_imapx_command_ref (link->data);
- camel_imapx_command_queue_delete_link (is->queue, link);
- imapx_server_command_removed (is, ic);
-
- success = imapx_command_start (
- is, ic, cancellable, error);
-
- camel_imapx_command_unref (ic);
-
- if (!success) {
- g_queue_clear (&start);
- return FALSE;
- }
+ /* Start the tagged command */
+ if (start_ic) {
+ camel_imapx_command_queue_remove (is->queue, start_ic);
+ imapx_server_command_removed (is, start_ic);
+ imapx_command_start (is, start_ic);
+ camel_imapx_command_unref (start_ic);
}
}
@@ -1430,7 +1391,6 @@ imapx_is_command_queue_empty (CamelIMAPX
static gboolean
imapx_command_queue (CamelIMAPXServer *is,
CamelIMAPXCommand *ic,
- GCancellable *cancellable,
GError **error)
{
CamelIMAPXJob *job;
@@ -1472,7 +1432,7 @@ imapx_command_queue (CamelIMAPXServer *i
camel_imapx_command_queue_insert_sorted (is->queue, ic);
imapx_server_command_added (is, ic);
- success = imapx_command_start_next (is, cancellable, error);
+ success = imapx_command_start_next (is);
QUEUE_UNLOCK (is);
@@ -2808,7 +2768,7 @@ imapx_continuation (CamelIMAPXServer *is
QUEUE_LOCK (is);
is->literal = NULL;
- success = imapx_command_start_next (is, cancellable, error);
+ success = imapx_command_start_next (is);
QUEUE_UNLOCK (is);
return success;
@@ -2950,7 +2910,7 @@ noskip:
is->literal = newliteral;
if (!litplus)
- success = imapx_command_start_next (is, cancellable, error);
+ success = imapx_command_start_next (is);
QUEUE_UNLOCK (is);
return success;
@@ -3063,7 +3023,7 @@ imapx_completion (CamelIMAPXServer *is,
camel_imapx_command_unref (ic);
QUEUE_LOCK (is);
- success = imapx_command_start_next (is, cancellable, error);
+ success = imapx_command_start_next (is);
QUEUE_UNLOCK (is);
return success;
@@ -3129,7 +3089,7 @@ imapx_command_run (CamelIMAPXServer *is,
camel_imapx_command_close (ic);
QUEUE_LOCK (is);
- imapx_command_start (is, ic, cancellable, error);
+ imapx_command_start (is, ic);
QUEUE_UNLOCK (is);
while (success && ic->status == NULL)
@@ -3200,7 +3160,7 @@ imapx_command_run_sync (CamelIMAPXServer
/* Unref'ed in imapx_command_complete(). */
camel_imapx_command_ref (ic);
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
if (success)
camel_imapx_command_wait (ic);
@@ -3252,10 +3212,14 @@ imapx_unregister_job (CamelIMAPXServer *
camel_imapx_job_done (job);
QUEUE_LOCK (is);
+
if (g_queue_remove (&is->jobs, job)) {
imapx_server_job_removed (is, job);
camel_imapx_job_unref (job);
}
+
+ imapx_command_start_next (is);
+
QUEUE_UNLOCK (is);
}
@@ -3361,7 +3325,7 @@ imapx_job_idle_start (CamelIMAPXJob *job
/* Don't issue it if the idle was cancelled already */
if (is->idle->state == IMAPX_IDLE_PENDING) {
is->idle->state = IMAPX_IDLE_ISSUED;
- success = imapx_command_start (is, ic, cancellable, error);
+ success = imapx_command_start (is, ic);
} else {
imapx_unregister_job (is, job);
camel_imapx_command_unref (ic);
@@ -3903,7 +3867,7 @@ imapx_select (CamelIMAPXServer *is,
camel_imapx_command_add_qresync_parameter (ic, folder);
ic->complete = imapx_command_select_done;
- imapx_command_start (is, ic, cancellable, error);
+ imapx_command_start (is, ic);
return TRUE;
}
@@ -4579,6 +4543,7 @@ imapx_command_fetch_message_done (CamelI
CamelFolder *folder;
GetMessageData *data;
CamelIMAPXFolder *ifolder;
+ GError *local_error = NULL;
gboolean success = TRUE;
job = camel_imapx_command_get_job (ic);
@@ -4594,11 +4559,11 @@ imapx_command_fetch_message_done (CamelI
* or we failed. Failure is handled in the fetch code, so
* we just return the job, or keep it alive with more requests */
- job->commands--;
+ g_atomic_int_add (&job->commands, -1);
- if (camel_imapx_command_set_error_if_failed (ic, cancellable, error)) {
+ if (camel_imapx_command_set_error_if_failed (ic, cancellable, &local_error)) {
g_prefix_error (
- error, "%s: ",
+ &local_error, "%s: ",
_("Error fetching message"));
data->body_len = -1;
success = FALSE;
@@ -4627,18 +4592,24 @@ imapx_command_fetch_message_done (CamelI
camel_imapx_command_set_job (new_ic, job);
new_ic->pri = job->pri - 1;
data->fetch_offset += MULTI_SIZE;
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
success = imapx_command_queue (
- is, new_ic, cancellable, error);
+ is, new_ic, &local_error);
goto exit;
}
}
/* If we have more messages to fetch, skip the rest. */
- if (job->commands > 0)
+ if (g_atomic_int_get (&job->commands) > 0) {
+ /* Make sure no command will starve in a queue */
+ QUEUE_LOCK (is);
+ imapx_command_start_next (is);
+ QUEUE_UNLOCK (is);
+
goto exit;
+ }
/* No more messages to fetch, let's wrap things up. */
@@ -4646,24 +4617,24 @@ imapx_command_fetch_message_done (CamelI
if (success) {
success = camel_stream_flush (
- data->stream, cancellable, error) == 0;
+ data->stream, cancellable, &local_error) == 0;
g_prefix_error (
- error, "%s: ",
+ &local_error, "%s: ",
_("Failed to close the tmp stream"));
}
if (success) {
success = camel_stream_close (
- data->stream, cancellable, error) == 0;
+ data->stream, cancellable, &local_error) == 0;
g_prefix_error (
- error, "%s: ",
+ &local_error, "%s: ",
_("Failed to close the tmp stream"));
}
- if (success && g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ if (success && g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
success = FALSE;
g_prefix_error (
- error, "%s: ",
+ &local_error, "%s: ",
_("Error fetching message"));
}
@@ -4686,11 +4657,11 @@ imapx_command_fetch_message_done (CamelI
/* Exchange the "tmp" stream for the "cur" stream. */
g_clear_object (&data->stream);
data->stream = camel_data_cache_get (
- ifolder->cache, "cur", data->uid, error);
+ ifolder->cache, "cur", data->uid, &local_error);
success = (data->stream != NULL);
} else {
g_set_error (
- error, G_FILE_ERROR,
+ &local_error, G_FILE_ERROR,
g_file_error_from_errno (errno),
"%s: %s",
_("Failed to copy the tmp file"),
@@ -4702,7 +4673,20 @@ imapx_command_fetch_message_done (CamelI
g_free (tmp_filename);
}
- camel_data_cache_remove (ifolder->cache, "tmp", data->uid, NULL);
+ /* Delete the 'tmp' file only if the operation wasn't cancelled. 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))
+ camel_data_cache_remove (ifolder->cache, "tmp", data->uid, NULL);
+
+ /* Avoid possible use-after-free when the imapx_unregister_job() can
+ also free the 'job' structure. */
+ if (local_error != NULL)
+ camel_imapx_job_set_error (job, local_error);
+
imapx_unregister_job (is, job);
exit:
@@ -4710,6 +4694,9 @@ exit:
camel_imapx_command_unref (ic);
+ if (local_error)
+ g_propagate_error (error, local_error);
+
return success;
}
@@ -4743,10 +4730,10 @@ imapx_job_get_message_start (CamelIMAPXJ
camel_imapx_command_set_job (ic, job);
ic->pri = job->pri;
data->fetch_offset += MULTI_SIZE;
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
success = imapx_command_queue (
- is, ic, cancellable, error);
+ is, ic, error);
if (!success)
break;
}
@@ -4758,9 +4745,9 @@ imapx_job_get_message_start (CamelIMAPXJ
ic->complete = imapx_command_fetch_message_done;
camel_imapx_command_set_job (ic, job);
ic->pri = job->pri;
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
}
g_object_unref (folder);
@@ -4903,14 +4890,14 @@ imapx_command_copy_messages_step_start (
if (res == 1) {
camel_imapx_command_add (ic, " %f", data->dest);
data->index = i + 1;
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
}
data->index = i;
if (imapx_uidset_done (&data->uidset, ic)) {
camel_imapx_command_add (ic, " %f", data->dest);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
return TRUE;
@@ -5055,11 +5042,11 @@ imapx_job_append_message_start (CamelIMA
ic->complete = imapx_command_append_message_done;
camel_imapx_command_set_job (ic, job);
ic->pri = job->pri;
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
/* ********************************************************************** */
@@ -5233,7 +5220,7 @@ imapx_command_step_fetch_done (CamelIMAP
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
}
}
@@ -5245,7 +5232,7 @@ imapx_command_step_fetch_done (CamelIMAP
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
}
@@ -5556,7 +5543,7 @@ imapx_job_scan_changes_start (CamelIMAPX
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
static gboolean
@@ -5730,7 +5717,7 @@ imapx_job_fetch_new_messages_start (Came
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
static gboolean
@@ -5863,7 +5850,7 @@ imapx_job_fetch_messages_start (CamelIMA
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
static gboolean
@@ -6208,7 +6195,7 @@ imapx_job_expunge_start (CamelIMAPXJob *
ic->pri = job->pri;
ic->complete = imapx_command_expunge_done;
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
}
g_object_unref (folder);
@@ -6279,7 +6266,7 @@ imapx_job_list_start (CamelIMAPXJob *job
camel_imapx_command_set_job (ic, job);
ic->complete = imapx_command_list_done;
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
static gboolean
@@ -6368,7 +6355,7 @@ imapx_job_manage_subscription_start (Cam
g_object_unref (store);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
/* ********************************************************************** */
@@ -6422,7 +6409,7 @@ imapx_job_create_folder_start (CamelIMAP
g_free (encoded_fname);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
/* ********************************************************************** */
@@ -6487,7 +6474,7 @@ imapx_job_delete_folder_start (CamelIMAP
camel_imapx_command_set_job (ic, job);
ic->complete = imapx_command_delete_folder_done;
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
g_object_unref (folder);
}
@@ -6561,7 +6548,7 @@ imapx_job_rename_folder_start (CamelIMAP
camel_imapx_command_set_job (ic, job);
ic->complete = imapx_command_rename_folder_done;
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
g_object_unref (folder);
}
@@ -6628,7 +6615,7 @@ imapx_job_update_quota_info_start (Camel
camel_imapx_command_set_job (ic, job);
ic->complete = imapx_command_update_quota_info_done;
- success = imapx_command_queue (is, ic, cancellable, error);
+ success = imapx_command_queue (is, ic, error);
g_free (encoded_folder_name);
@@ -6699,7 +6686,7 @@ imapx_job_uid_search_start (CamelIMAPXJo
g_object_unref (folder);
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
/* ********************************************************************** */
@@ -6752,7 +6739,7 @@ imapx_job_noop_start (CamelIMAPXJob *job
ic->pri = IMAPX_PRIORITY_NOOP;
}
- return imapx_command_queue (is, ic, cancellable, error);
+ return imapx_command_queue (is, ic, error);
}
/* ********************************************************************** */
@@ -6810,7 +6797,7 @@ imapx_command_sync_changes_done (CamelIM
mobile_mode = camel_imapx_settings_get_mobile_mode (settings);
g_object_unref (settings);
- job->commands--;
+ g_atomic_int_add (&job->commands, -1);
full_name = camel_folder_get_full_name (folder);
parent_store = camel_folder_get_parent_store (folder);
@@ -6862,7 +6849,7 @@ imapx_command_sync_changes_done (CamelIM
((CamelIMAPXFolder *) folder)->unread_on_server += data->unread_change;
}
- if (job->commands == 0) {
+ if (g_atomic_int_get (&job->commands) == 0) {
if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
CamelStoreInfo *si;
@@ -6888,6 +6875,11 @@ imapx_command_sync_changes_done (CamelIM
camel_store_summary_save ((CamelStoreSummary *)((CamelIMAPXStore *) parent_store)->summary);
imapx_unregister_job (is, job);
+ } else {
+ /* Make sure no command will starve in a queue */
+ QUEUE_LOCK (is);
+ imapx_command_start_next (is);
+ QUEUE_UNLOCK (is);
}
g_object_unref (folder);
@@ -6974,9 +6966,9 @@ imapx_job_sync_changes_start (CamelIMAPX
send = imapx_uidset_add (&ss, ic, camel_message_info_uid (info));
}
if (send == 1 || (i == uids->len - 1 && imapx_uidset_done (&ss, ic))) {
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
- if (!imapx_command_queue (is, ic, cancellable, error)) {
+ if (!imapx_command_queue (is, ic, error)) {
camel_message_info_free (info);
goto exit;
}
@@ -7015,9 +7007,9 @@ imapx_job_sync_changes_start (CamelIMAPX
if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info)) == 1
|| (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
- job->commands++;
+ g_atomic_int_add (&job->commands, 1);
camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
- if (!imapx_command_queue (is, ic, cancellable, error))
+ if (!imapx_command_queue (is, ic, error))
goto exit;
ic = NULL;
}
@@ -7029,11 +7021,14 @@ imapx_job_sync_changes_start (CamelIMAPX
exit:
g_object_unref (folder);
- /* Since this may start in another thread ... we need to
- * lock the commands count, ho hum */
-
- if (job->commands == 0)
+ if (g_atomic_int_get (&job->commands) == 0) {
imapx_unregister_job (is, job);
+ } else {
+ /* Make sure no command will starve in a queue */
+ QUEUE_LOCK (is);
+ imapx_command_start_next (is);
+ QUEUE_UNLOCK (is);
+ }
return TRUE;
}
@@ -7701,6 +7696,11 @@ imapx_server_get_message (CamelIMAPXServ
return NULL;
}
+ /* This makes sure that if any file is left on the disk, it is not reused.
+ That can happen when the previous message download had been cancelled
+ or finished with an error. */
+ camel_data_cache_remove (ifolder->cache, "tmp", uid, NULL);
+
data = g_slice_new0 (GetMessageData);
data->uid = g_strdup (uid);
data->stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
@@ -8964,3 +8964,106 @@ camel_imapx_server_shutdown (CamelIMAPXS
g_clear_object (&cancellable);
g_clear_error (&shutdown_error_copy);
}
+
+static const gchar *
+imapx_server_get_job_type_name (CamelIMAPXJob *job)
+{
+ if (!job)
+ return "[null]";
+
+ switch (job->type) {
+ case IMAPX_JOB_GET_MESSAGE:
+ return "GET_MESSAGE";
+ case IMAPX_JOB_APPEND_MESSAGE:
+ return "APPEND_MESSAGE";
+ case IMAPX_JOB_COPY_MESSAGE:
+ return "COPY_MESSAGE";
+ case IMAPX_JOB_FETCH_NEW_MESSAGES:
+ return "FETCH_NEW_MESSAGES";
+ case IMAPX_JOB_REFRESH_INFO:
+ return "REFRESH_INFO";
+ case IMAPX_JOB_SYNC_CHANGES:
+ return "SYNC_CHANGES";
+ case IMAPX_JOB_EXPUNGE:
+ return "EXPUNGE";
+ case IMAPX_JOB_NOOP:
+ return "NOOP";
+ case IMAPX_JOB_IDLE:
+ return "IDLE";
+ case IMAPX_JOB_LIST:
+ return "LIST";
+ case IMAPX_JOB_CREATE_FOLDER:
+ return "CREATE_FOLDER";
+ case IMAPX_JOB_DELETE_FOLDER:
+ return "DELETE_FOLDER";
+ case IMAPX_JOB_RENAME_FOLDER:
+ return "RENAME_FOLDER";
+ case IMAPX_JOB_MANAGE_SUBSCRIPTION:
+ return "MANAGE_SUBSCRIPTION";
+ case IMAPX_JOB_UPDATE_QUOTA_INFO:
+ return "UPDATE_QUOTA_INFO";
+ case IMAPX_JOB_UID_SEARCH:
+ return "UID_SEARCH";
+ }
+
+ return "???";
+}
+
+static void
+imapx_server_dump_one_queue (CamelIMAPXCommandQueue *queue,
+ const gchar *queue_name)
+{
+ GList *iter;
+ gint ii;
+
+ g_return_if_fail (queue != NULL);
+ g_return_if_fail (queue_name != NULL);
+
+ if (camel_imapx_command_queue_is_empty (queue))
+ return;
+
+ printf (" Content of '%s':\n", queue_name);
+
+ for (ii = 0, iter = camel_imapx_command_queue_peek_head_link (queue); iter != NULL; iter = g_list_next (iter), ii++) {
+ CamelIMAPXCommand *ic = iter->data;
+ CamelIMAPXJob *job = camel_imapx_command_get_job (ic);
+
+ printf (" [%d] command:%p for job:%p (type:0x%x %s)\n", ii, ic, job, job ? job->type : 0, imapx_server_get_job_type_name (job));
+ }
+}
+
+/* for debugging purposes only */
+void
+camel_imapx_server_dump_queue_status (CamelIMAPXServer *imapx_server)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server));
+
+ QUEUE_LOCK (imapx_server);
+
+ printf (" Queue status for server %p: jobs:%d queued:%d active:%d done:%d\n", imapx_server,
+ g_queue_get_length (&imapx_server->jobs),
+ camel_imapx_command_queue_get_length (imapx_server->queue),
+ camel_imapx_command_queue_get_length (imapx_server->active),
+ camel_imapx_command_queue_get_length (imapx_server->done));
+
+ if (!g_queue_is_empty (&imapx_server->jobs)) {
+ GList *iter;
+ gint ii;
+
+ printf (" Content of 'jobs':\n");
+
+ for (ii = 0, iter = g_queue_peek_head_link (&imapx_server->jobs); iter != NULL; iter = g_list_next (iter), ii++) {
+ CamelIMAPXJob *job = iter->data;
+
+ printf (" [%d] job:%p (type:0x%x %s) with pending commands:%d\n", ii, job, job ? job->type : 0,
+ imapx_server_get_job_type_name (job),
+ job ? g_atomic_int_get (&job->commands) : -1);
+ }
+ }
+
+ imapx_server_dump_one_queue (imapx_server->queue, "queue");
+ imapx_server_dump_one_queue (imapx_server->active, "active");
+ imapx_server_dump_one_queue (imapx_server->done, "done");
+
+ QUEUE_UNLOCK (imapx_server);
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-server.h.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-server.h
--- evolution-data-server-3.8.5/camel/camel-imapx-server.h.imapx-error-cancelled-message-download 2014-05-16 11:36:17.875612926 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-server.h 2014-05-16 11:36:17.885612837 +0200
@@ -312,6 +312,9 @@ struct _CamelIMAPXJob *
CamelFolder *folder,
guint32 job_type,
const gchar *uid);
+/* for debugging purposes only */
+void camel_imapx_server_dump_queue_status
+ (CamelIMAPXServer *imapx_server);
G_END_DECLS
diff -up evolution-data-server-3.8.5/camel/camel-imapx-store.c.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-store.c
--- evolution-data-server-3.8.5/camel/camel-imapx-store.c.imapx-error-cancelled-message-download 2014-05-16 11:36:17.876612917 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-store.c 2014-05-16 11:36:17.886612828 +0200
@@ -2226,3 +2226,12 @@ camel_imapx_store_ref_job (CamelIMAPXSto
return job;
}
+
+/* for debugging purposes only */
+void
+camel_imapx_store_dump_queue_status (CamelIMAPXStore *imapx_store)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
+
+ camel_imapx_conn_manager_dump_queue_status (imapx_store->con_man);
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-store.h.imapx-error-cancelled-message-download evolution-data-server-3.8.5/camel/camel-imapx-store.h
--- evolution-data-server-3.8.5/camel/camel-imapx-store.h.imapx-error-cancelled-message-download 2014-05-16 11:36:17.876612917 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-store.h 2014-05-16 11:36:17.886612828 +0200
@@ -120,6 +120,9 @@ struct _CamelIMAPXJob *
CamelFolder *folder,
guint32 job_type,
const gchar *uid);
+/* for debugging purposes only */
+void camel_imapx_store_dump_queue_status
+ (CamelIMAPXStore *imapx_store);
G_END_DECLS