X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-mail-operation-queue.c;h=c4611bfa3d2821de341a8a9fa84f43b63d6239c4;hp=a05c8fd35370deee1eed048cfb9d4b1ded7f7f0e;hb=HEAD;hpb=a8c98320eac2c32a0427101113a3b9f134290771 diff --git a/src/modest-mail-operation-queue.c b/src/modest-mail-operation-queue.c index a05c8fd..c4611bf 100644 --- a/src/modest-mail-operation-queue.c +++ b/src/modest-mail-operation-queue.c @@ -31,6 +31,7 @@ #include "modest-marshal.h" #include "modest-mail-operation-queue.h" #include "modest-runtime.h" +#include "modest-debug.h" /* 'private'/'protected' functions */ static void modest_mail_operation_queue_class_init (ModestMailOperationQueueClass *klass); @@ -53,6 +54,8 @@ struct _ModestMailOperationQueuePrivate { GQueue *op_queue; GMutex *queue_lock; guint op_id; + guint queue_empty_handler; + gboolean running_final_sync; }; #define MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_MAIL_OPERATION_QUEUE, \ @@ -145,6 +148,18 @@ modest_mail_operation_queue_init (ModestMailOperationQueue *obj) priv->op_queue = g_queue_new (); priv->queue_lock = g_mutex_new (); priv->op_id = 0; + priv->queue_empty_handler = 0; + priv->running_final_sync = FALSE; +} + +static void +print_queue_item (ModestMailOperation *op, const gchar* prefix) +{ + gchar *op_str = modest_mail_operation_to_string (op); + g_debug ("%s: %s", + prefix ? prefix : "", + op_str); + g_free (op_str); } static void @@ -164,6 +179,8 @@ on_finalize_foreach(gpointer op, * the lock acquired. */ g_signal_handlers_disconnect_by_func (mail_op, G_CALLBACK (on_operation_finished), user_data); + MODEST_DEBUG_BLOCK (print_queue_item (mail_op, "cancel/remove");); + modest_mail_operation_cancel (mail_op); g_queue_remove (priv->op_queue, mail_op); g_object_unref (G_OBJECT (mail_op)); @@ -178,6 +195,13 @@ modest_mail_operation_queue_finalize (GObject *obj) g_mutex_lock (priv->queue_lock); + MODEST_DEBUG_BLOCK ( + g_debug ("%s; items in queue: %d", + __FUNCTION__, g_queue_get_length (priv->op_queue)); + g_queue_foreach (priv->op_queue, (GFunc)print_queue_item, "in queue"); + ); + + if (priv->op_queue) { /* Cancel all */ if (!g_queue_is_empty (priv->op_queue)) { @@ -204,6 +228,28 @@ modest_mail_operation_queue_new (void) } static void +on_operation_started (ModestMailOperation *mail_op, + gpointer user_data) +{ + ModestMailOperationQueue *self = MODEST_MAIL_OPERATION_QUEUE (user_data); + ModestMailOperationTypeOperation op_type; + ModestMailOperationQueuePrivate *priv; + TnyDevice *device; + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + + op_type = modest_mail_operation_get_type_operation (mail_op); + device = modest_runtime_get_device (); + + if ((op_type != MODEST_MAIL_OPERATION_TYPE_SHUTDOWN) && + priv->running_final_sync && + tny_device_is_forced (device)) + tny_device_reset (device); + + priv->running_final_sync = (op_type == MODEST_MAIL_OPERATION_TYPE_SHUTDOWN); +} + +static void on_operation_finished (ModestMailOperation *mail_op, gpointer user_data) { @@ -221,20 +267,27 @@ modest_mail_operation_queue_add (ModestMailOperationQueue *self, g_return_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self)); g_return_if_fail (MODEST_IS_MAIL_OPERATION (mail_op)); - + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); g_mutex_lock (priv->queue_lock); g_queue_push_tail (priv->op_queue, g_object_ref (mail_op)); g_mutex_unlock (priv->queue_lock); + MODEST_DEBUG_BLOCK (print_queue_item (mail_op, "add");); + + g_signal_connect (G_OBJECT (mail_op), + "operation-started", + G_CALLBACK (on_operation_started), + self); + /* Get notified when the operation ends to remove it from the queue. We connect it using the *after* because we want to let the other handlers for the finish function happen before this */ - g_signal_connect_after (G_OBJECT (mail_op), + g_signal_connect_after (G_OBJECT (mail_op), "operation-finished", - G_CALLBACK (on_operation_finished), + G_CALLBACK (on_operation_finished), self); /* Notify observers */ @@ -242,12 +295,45 @@ modest_mail_operation_queue_add (ModestMailOperationQueue *self, mail_op, MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED); } -void +static gboolean +notify_queue_empty (gpointer user_data) +{ + ModestMailOperationQueue *self = (ModestMailOperationQueue *) user_data; + ModestMailOperationQueuePrivate *priv; + guint num_elements; + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + + g_mutex_lock (priv->queue_lock); + num_elements = priv->op_queue->length; + g_mutex_unlock (priv->queue_lock); + + /* We re-check again that the queue is empty. It could happen + that we had issued a tny_send_queue_flush before the send + queue could add a mail operation to the queue as a response + to the "start-queue" signal, because that signal is issued + by tinymail in the main loop. Therefor it could happen that + we emit the queue-empty signal while a send-queue is still + waiting for the "start-queue" signal from tinymail, so the + send queue will never try to send the items because modest + is finalized before */ + if (num_elements == 0) { + gdk_threads_enter (); + g_signal_emit (self, signals[QUEUE_EMPTY_SIGNAL], 0); + gdk_threads_leave (); + } + + return FALSE; +} + + +void modest_mail_operation_queue_remove (ModestMailOperationQueue *self, ModestMailOperation *mail_op) { ModestMailOperationQueuePrivate *priv; ModestMailOperationStatus status; + guint num_elements; g_return_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self)); g_return_if_fail (MODEST_IS_MAIL_OPERATION (mail_op)); @@ -256,8 +342,11 @@ modest_mail_operation_queue_remove (ModestMailOperationQueue *self, g_mutex_lock (priv->queue_lock); g_queue_remove (priv->op_queue, mail_op); + num_elements = priv->op_queue->length; g_mutex_unlock (priv->queue_lock); + MODEST_DEBUG_BLOCK (print_queue_item (mail_op, "remove");); + g_signal_handlers_disconnect_by_func (G_OBJECT (mail_op), G_CALLBACK (on_operation_finished), self); @@ -268,7 +357,8 @@ modest_mail_operation_queue_remove (ModestMailOperationQueue *self, /* Check errors */ status = modest_mail_operation_get_status (mail_op); - if (status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) { + if (status != MODEST_MAIL_OPERATION_STATUS_SUCCESS && + status != MODEST_MAIL_OPERATION_STATUS_INVALID) { /* This is a sanity check. Shouldn't be needed, but prevent possible application crashes. It's useful also for detecting mail operations with invalid @@ -277,7 +367,7 @@ modest_mail_operation_queue_remove (ModestMailOperationQueue *self, modest_mail_operation_execute_error_handler (mail_op); } else { if (status == MODEST_MAIL_OPERATION_STATUS_CANCELED) - g_warning ("%s: operation canceled \n", __FUNCTION__); + g_debug ("%s: operation canceled \n", __FUNCTION__); else g_warning ("%s: possible error in a mail operation " \ "implementation. The status is not successful " \ @@ -287,26 +377,29 @@ modest_mail_operation_queue_remove (ModestMailOperationQueue *self, } /* Free object */ - - /* We do not own the last reference when this operation is deleted - * as response to a progress changed signal from the mail operation - * itself, in which case the glib signal system owns a reference - * until the signal emission is complete. armin. */ - /* modest_runtime_verify_object_last_ref (mail_op, ""); */ g_object_unref (G_OBJECT (mail_op)); - /* Emit the queue empty-signal */ - g_signal_emit (self, signals[QUEUE_EMPTY_SIGNAL], 0); + /* Emit the queue empty-signal. See the function to know why + we emit it in an idle */ + if (num_elements == 0) { + if (priv->queue_empty_handler) { + g_source_remove (priv->queue_empty_handler); + priv->queue_empty_handler = 0; + } + priv->queue_empty_handler = g_idle_add_full (G_PRIORITY_LOW, + notify_queue_empty, + self, NULL); + } } -guint +guint modest_mail_operation_queue_num_elements (ModestMailOperationQueue *self) { ModestMailOperationQueuePrivate *priv; guint length = 0; g_return_val_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self), 0); - + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); g_mutex_lock (priv->queue_lock); @@ -327,6 +420,8 @@ modest_mail_operation_queue_cancel (ModestMailOperationQueue *self, priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + MODEST_DEBUG_BLOCK (print_queue_item (mail_op, "cancel");); + /* This triggers a progess_changed signal in which we remove * the operation from the queue. */ modest_mail_operation_cancel (mail_op); @@ -361,7 +456,7 @@ modest_mail_operation_queue_cancel_all (ModestMailOperationQueue *self) g_queue_foreach (priv->op_queue, (GFunc) on_cancel_all_foreach, &operations_to_cancel); g_mutex_unlock (priv->queue_lock); - /* TODO: Reverse the list, to remove operations in order? */ + operations_to_cancel = g_slist_reverse (operations_to_cancel); for(cur = operations_to_cancel; cur != NULL; cur = cur->next) { if (!MODEST_IS_MAIL_OPERATION(cur->data)) @@ -382,36 +477,98 @@ typedef struct static void on_find_by_source_foreach (gpointer op, gpointer data) { - FindBySourceInfo *info = (FindBySourceInfo*) data; + FindBySourceInfo *info = (FindBySourceInfo*) data; + GObject *source = NULL; - if ( info->source == modest_mail_operation_get_source (MODEST_MAIL_OPERATION (op))) { + source = modest_mail_operation_get_source (MODEST_MAIL_OPERATION (op)); + if (info->source == source) { g_object_ref (G_OBJECT (op)); *(info->new_list) = g_slist_prepend (*(info->new_list), MODEST_MAIL_OPERATION (op)); } + if (source) + g_object_unref (source); } GSList* -modest_mail_operation_queue_get_by_source ( - ModestMailOperationQueue *self, - GObject *source) +modest_mail_operation_queue_get_by_source (ModestMailOperationQueue *self, + GObject *source) { ModestMailOperationQueuePrivate *priv; GSList* found_operations= NULL; - FindBySourceInfo *info = g_new0 (FindBySourceInfo, 1); + FindBySourceInfo *info; g_return_val_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self), NULL); g_return_val_if_fail (source != NULL, NULL); - + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + info = g_new0 (FindBySourceInfo, 1); info->new_list = &found_operations; info->source = source; - + g_mutex_lock (priv->queue_lock); g_queue_foreach (priv->op_queue, (GFunc) on_find_by_source_foreach, info); g_mutex_unlock (priv->queue_lock); - + g_free (info); - + return found_operations; } + +static void +accumulate_mail_op_strings (ModestMailOperation *op, gchar **str) +{ + gchar *mail_op_to_str = modest_mail_operation_to_string (op); + *str = g_strdup_printf ("%s\n%s", *str, mail_op_to_str); + g_free (mail_op_to_str); +} + + +gchar* +modest_mail_operation_queue_to_string (ModestMailOperationQueue *self) +{ + gchar *str = NULL; + guint len; + ModestMailOperationQueuePrivate *priv; + + g_return_val_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self), NULL); + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + + len = g_queue_get_length (priv->op_queue); + str = g_strdup_printf ("mail operation queue (%02d)\n-------------------------", len); + if (len == 0) { + gchar *copy; + copy = str; + str = g_strdup_printf ("%s\n%s", copy, ""); + g_free (copy); + } else { + g_mutex_lock (priv->queue_lock); + g_queue_foreach (priv->op_queue, (GFunc)accumulate_mail_op_strings, &str); + g_mutex_unlock (priv->queue_lock); + } + + return str; +} + +gboolean +modest_mail_operation_queue_running_shutdown (ModestMailOperationQueue *self) +{ + ModestMailOperationQueuePrivate *priv; + + g_return_val_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self), FALSE); + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + return priv->running_final_sync; +} + +void +modest_mail_operation_queue_set_running_shutdown (ModestMailOperationQueue *self) +{ + ModestMailOperationQueuePrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self)); + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + priv->running_final_sync = TRUE; +}