* Fixes NB#85964, do not crash when opening Drafts in memory full condition
[modest] / src / modest-mail-operation.c
index 02ae707..8b38cd6 100644 (file)
@@ -107,6 +107,8 @@ static void     sync_folder_finish_callback (TnyFolder *self,
                                             GError *err, 
                                             gpointer user_data);
 
+static gboolean _check_memory_low         (ModestMailOperation *mail_op);
+
 enum _ModestMailOperationSignals 
 {
        PROGRESS_CHANGED_SIGNAL,
@@ -508,7 +510,8 @@ modest_mail_operation_cancel (ModestMailOperation *self)
                                                       TRUE);
 
                /* Cancel the sending of the following next messages */
-               tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
+               if (TNY_IS_SEND_QUEUE (queue))
+                       tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
        }
        
        return canceled;
@@ -1438,24 +1441,26 @@ inbox_refreshed_cb (TnyFolder *inbox,
                send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
                g_object_unref (transport_account);
 
-               /* Get outbox folder */
-               outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
-               if (outbox) { /* this could fail in some cases */
-                       num_messages = tny_folder_get_all_count (outbox);
-                       g_object_unref (outbox);
-               } else {
-                       g_warning ("%s: could not get outbox", __FUNCTION__);
-                       num_messages = 0;
-               }
+               if (TNY_IS_SEND_QUEUE (send_queue)) {
+                       /* Get outbox folder */
+                       outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
+                       if (outbox) { /* this could fail in some cases */
+                               num_messages = tny_folder_get_all_count (outbox);
+                               g_object_unref (outbox);
+                       } else {
+                               g_warning ("%s: could not get outbox", __FUNCTION__);
+                               num_messages = 0;
+                       }
                
-               if (num_messages != 0) {
-                       /* Reenable suspended items */
-                       modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
-
-                       /* Try to send */
-                       tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
-                       modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), 
-                                                                         info->interactive);
+                       if (num_messages != 0) {
+                               /* Reenable suspended items */
+                               modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
+                               
+                               /* Try to send */
+                               tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
+                               modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), 
+                                                                                 info->interactive);
+                       }
                }
        }
 
@@ -2235,13 +2240,20 @@ modest_mail_operation_get_msg (ModestMailOperation *self,
        g_return_if_fail (TNY_IS_HEADER (header));
        
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
-       folder = tny_header_get_folder (header);
-
        priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
        priv->total = 1;
        priv->done = 0;
 
+       /* Check memory low */
+       if (_check_memory_low (self)) {
+               if (user_callback)
+                       user_callback (self, header, FALSE, NULL, priv->error, user_data);
+               modest_mail_operation_notify_end (self);
+               return;
+       }
+
        /* Get account and set it into mail_operation */
+       folder = tny_header_get_folder (header);
        priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
        
        /* Check for cached messages */
@@ -2405,6 +2417,28 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self,
        priv->done = 0;
        priv->total = tny_list_get_length(header_list);
 
+       /* Check memory low */
+       if (_check_memory_low (self)) {
+               if (user_callback) {
+                       TnyHeader *header = NULL;
+                       TnyIterator *iter;
+
+                       if (tny_list_get_length (header_list) > 0) {
+                               iter = tny_list_create_iterator (header_list);
+                               header = (TnyHeader *) tny_iterator_get_current (iter);
+                               g_object_unref (iter);
+                       }
+                       user_callback (self, header, FALSE, NULL, priv->error, user_data);
+                       if (header)
+                               g_object_unref (header);
+               }
+               if (notify)
+                       notify (user_data);
+               /* Notify about operation end */
+               modest_mail_operation_notify_end (self);
+               return;
+       }
+
        /* Check uncached messages */
        for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
             !has_uncached_messages && !tny_iterator_is_done (iter); 
@@ -2576,22 +2610,25 @@ modest_mail_operation_remove_msgs (ModestMailOperation *self,
                if (traccount) {
                        ModestTnySendQueueStatus status;
                        ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
-                       TnyIterator *iter = tny_list_create_iterator(headers);
-                       g_object_unref(remove_headers);
-                       remove_headers = TNY_LIST(tny_simple_list_new());
-                       while (!tny_iterator_is_done(iter)) {
-                               char *msg_id;
-                               TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
-                               msg_id = modest_tny_send_queue_get_msg_id (hdr);
-                               status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
-                               if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
-                                       tny_list_append(remove_headers, G_OBJECT(hdr));
+
+                       if (TNY_IS_SEND_QUEUE (send_queue)) {
+                               TnyIterator *iter = tny_list_create_iterator(headers);
+                               g_object_unref(remove_headers);
+                               remove_headers = TNY_LIST(tny_simple_list_new());
+                               while (!tny_iterator_is_done(iter)) {
+                                       char *msg_id;
+                                       TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
+                                       msg_id = modest_tny_send_queue_get_msg_id (hdr);
+                                       status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
+                                       if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
+                                               tny_list_append(remove_headers, G_OBJECT(hdr));
+                                       }
+                                       g_object_unref(hdr);
+                                       g_free(msg_id);
+                                       tny_iterator_next(iter);
                                }
-                               g_object_unref(hdr);
-                               g_free(msg_id);
-                               tny_iterator_next(iter);
+                               g_object_unref(iter);
                        }
-                       g_object_unref(iter);
                        g_object_unref(traccount);
                }
        }
@@ -2690,6 +2727,35 @@ transfer_msgs_status_cb (GObject *obj,
                                              &(helper->sum_total_bytes), helper->total_bytes, TRUE);
 }
 
+static void
+transfer_msgs_sync_folder_cb (TnyFolder *self, 
+                             gboolean cancelled, 
+                             GError *err, 
+                             gpointer user_data)
+{
+       XFerMsgsAsyncHelper *helper;
+       /* We don't care here about the results of the
+          synchronization */
+       helper = (XFerMsgsAsyncHelper *) user_data;
+
+       /* Notify about operation end */
+       modest_mail_operation_notify_end (helper->mail_op);
+
+       /* If user defined callback function was defined, call it */
+       if (helper->user_callback)
+               helper->user_callback (helper->mail_op, helper->user_data);
+       
+       /* Free */
+       if (helper->more_msgs)
+               g_object_unref (helper->more_msgs);
+       if (helper->headers)
+               g_object_unref (helper->headers);
+       if (helper->dest_folder)
+               g_object_unref (helper->dest_folder);
+       if (helper->mail_op)
+               g_object_unref (helper->mail_op);
+       g_slice_free (XFerMsgsAsyncHelper, helper);
+}
 
 static void
 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
@@ -2731,34 +2797,13 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer u
        }
 
        if (finished) {
-
-               /* Update folder counts */
-               tny_folder_poke_status (folder);
-               tny_folder_poke_status (helper->dest_folder);
-
-               /* Notify about operation end */
-               modest_mail_operation_notify_end (self);
-
-               /* If user defined callback function was defined, call it */
-               if (helper->user_callback) {
-                       /* This is not a GDK lock because we are a Tinymail callback and
-                        * Tinymail already acquires the Gdk lock */
-
-                       /* no gdk_threads_enter (), CHECKED */
-                       helper->user_callback (self, helper->user_data);
-                       /* no gdk_threads_leave (), CHECKED */
-               }
-
-               /* Free */
-               if (helper->more_msgs)
-                       g_object_unref (helper->more_msgs);
-               if (helper->headers)
-                       g_object_unref (helper->headers);
-               if (helper->dest_folder)
-                       g_object_unref (helper->dest_folder);
-               if (helper->mail_op)
-                       g_object_unref (helper->mail_op);
-               g_slice_free (XFerMsgsAsyncHelper, helper);
+               /* Synchronize the source folder contents. This should
+                  be done by tinymail but the camel_folder_sync it's
+                  actually disabled in transfer_msgs_thread_clean
+                  because it's supposed to cause hangs */
+               tny_folder_sync_async (folder, helper->delete, 
+                                      transfer_msgs_sync_folder_cb, 
+                                      NULL, helper);
        } else {
                /* Transfer more messages */
                tny_folder_transfer_msgs_async (folder,
@@ -3039,9 +3084,17 @@ modest_mail_operation_refresh_folder  (ModestMailOperation *self,
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
+       /* Check memory low */
+       if (_check_memory_low (self)) {
+               if (user_callback)
+                       user_callback (self, folder, user_data);
+               /* Notify about operation end */
+               modest_mail_operation_notify_end (self);
+               return;
+       }
 
        /* Get account and set it into mail_operation */
+       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
        priv->account = modest_tny_folder_get_account  (folder);
        priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
 
@@ -3085,6 +3138,7 @@ run_queue_stop (ModestTnySendQueue *queue,
        g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
        g_object_unref (self);
 }
+
 void
 modest_mail_operation_run_queue (ModestMailOperation *self,
                                 ModestTnySendQueue *queue)
@@ -3105,6 +3159,42 @@ modest_mail_operation_run_queue (ModestMailOperation *self,
 }
 
 static void
+shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
+{
+       ModestMailOperation *self = (ModestMailOperation *) userdata;
+       ModestMailOperationPrivate *priv;
+
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+
+       priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+
+       modest_mail_operation_notify_end (self);
+       g_object_unref (self);
+}
+
+void
+modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
+{
+       ModestMailOperationPrivate *priv;
+
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+
+       modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
+
+       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
+       priv->account = NULL;
+       priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
+
+       modest_mail_operation_notify_start (self);
+       g_object_ref (self);
+       modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
+}
+
+static void
 sync_folder_finish_callback (TnyFolder *self, 
                             gboolean cancelled, 
                             GError *err, 
@@ -3277,3 +3367,25 @@ modest_mail_operation_to_string (ModestMailOperation *self)
                                priv->done, priv->total,
                                priv->error && priv->error->message ? priv->error->message : "");
 }
+
+/* 
+ * Once the mail operations were objects this will be no longer
+ * needed. I don't like it, but we need it for the moment
+ */
+static gboolean
+_check_memory_low (ModestMailOperation *mail_op)
+{
+       if (modest_platform_check_memory_low (NULL, FALSE)) {
+               ModestMailOperationPrivate *priv;
+
+               priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error),
+                            MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
+                            "Not enough memory to complete the operation");
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}