Fix reference leaks causing power consuption because of running IDLE.
[modest] / src / modest-mail-operation.c
index 41254a8..aa1d1cd 100644 (file)
 #include <libgnomevfs/gnome-vfs.h>
 #include "modest-utils.h"
 #include "modest-debug.h"
+#ifdef MODEST_USE_LIBTIME
+#include <clockd/libtime.h>
+#endif
+#include "modest-account-protocol.h"
 
 #define KB 1024
 
@@ -132,7 +136,6 @@ typedef struct
        gint pending_calls;
        gboolean poke_all;
        TnyFolderObserver *inbox_observer;
-       RetrieveAllCallback retrieve_all_cb;
        gboolean interactive;
        gboolean msg_readed;
 } UpdateAccountInfo;
@@ -662,7 +665,7 @@ send_mail_on_sync_async_cb (TnyFolder *folder,
        self = helper->mail_op;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
-       if (cancelled || err)
+       if (cancelled)
                goto end;
 
        if (err) {
@@ -747,7 +750,7 @@ send_mail_on_added_to_outbox (TnySendQueue *send_queue,
        self = helper->mail_op;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
-       if (cancelled || err)
+       if (cancelled)
                goto end;
 
        if (err) {
@@ -1136,6 +1139,46 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self,
 
 typedef struct
 {
+       ModestMailOperation *mailop;
+       TnyMsg *msg;
+       SaveToDraftstCallback callback;
+       gpointer userdata;
+} FinishSaveRemoteDraftInfo;
+
+static void
+finish_save_remote_draft (ModestAccountProtocol *protocol,
+                         GError *err,
+                         const gchar *account_id,
+                         TnyMsg *new_remote_msg,
+                         TnyMsg *new_msg,
+                         TnyMsg *old_msg,
+                         gpointer userdata)
+{
+       FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
+       ModestMailOperationPrivate *priv = NULL;
+
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
+
+       if (!priv->error && err != NULL) {
+               /* Priority for errors in save to local stage */
+               priv->error = g_error_copy (err);
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+       }
+
+       if (info->callback)
+               info->callback (info->mailop, info->msg, info->userdata);
+
+       if (info->msg)
+               g_object_unref (info->msg);
+
+       modest_mail_operation_notify_end (info->mailop);
+       g_object_unref (info->mailop);
+
+       g_slice_free (FinishSaveRemoteDraftInfo, info);
+}
+
+typedef struct
+{
        TnyTransportAccount *transport_account;
        TnyMsg *draft_msg;
        SaveToDraftstCallback callback;
@@ -1154,6 +1197,7 @@ modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
        ModestMailOperationPrivate *priv = NULL;
        SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
        GError *io_error = NULL;
+       gboolean callback_called = FALSE;
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
 
@@ -1198,8 +1242,32 @@ modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
 
+       if (info->transport_account) {
+               ModestProtocolType transport_protocol_type;
+               ModestProtocol *transport_protocol;
+
+               transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
+
+               transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
+                                                                                   transport_protocol_type);
+               if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
+                       FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
+                       srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
+                       srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
+                       srd_info->callback = info->callback;
+                       srd_info->userdata = info->user_data;
+                       modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol), 
+                                                                  tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
+                                                                  info->msg, info->draft_msg,
+                                                                  finish_save_remote_draft,
+                                                                  srd_info);
+                                                                  
+                       callback_called = TRUE;
+               }
+       }
+
        /* Call the user callback */
-       if (info->callback)
+       if (!callback_called && info->callback)
                info->callback (info->mailop, info->msg, info->user_data);
 
        if (info->transport_account)
@@ -1211,8 +1279,10 @@ modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
        if (info->msg)
                g_object_unref (G_OBJECT (info->msg));
 
-       modest_mail_operation_notify_end (info->mailop);
-       g_object_unref(info->mailop);
+       if (!callback_called)
+               modest_mail_operation_notify_end (info->mailop);
+        if (info->mailop)
+               g_object_unref(info->mailop);
        g_slice_free (SaveToDraftsAddMsgInfo, info);
 }
 
@@ -1569,7 +1639,8 @@ inbox_refreshed_cb (TnyFolder *inbox,
        ModestAccountMgr *mgr;
        ModestAccountRetrieveType retrieve_type;
        TnyList *new_headers = NULL;
-       gboolean headers_only, ignore_limit;
+       gboolean headers_only;
+       time_t time_to_store;
 
        info = (UpdateAccountInfo *) user_data;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
@@ -1600,7 +1671,14 @@ inbox_refreshed_cb (TnyFolder *inbox,
        }
 
        /* Set the last updated as the current time */
-       modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
+#ifdef MODEST_USE_LIBTIME
+       struct tm utc_tm;
+       time_get_utc (&utc_tm);
+       time_to_store = time_mktime (&utc_tm, "GMT");
+#else
+       time_to_store = time (NULL);
+#endif
+       modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
 
        /* Get the message max size */
        max_size  = modest_conf_get_int (modest_runtime_get_conf (),
@@ -1650,25 +1728,13 @@ inbox_refreshed_cb (TnyFolder *inbox,
        /* Order by date */
        g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
 
-       /* Ask the users if they want to retrieve all the messages
-          even though the limit was exceeded */
-       ignore_limit = FALSE;
-       if (new_headers_array->len > retrieve_limit) {
-               /* Ask the user if a callback has been specified and
-                  if the mail operation has a source (this means that
-                  was invoked by the user and not automatically by a
-                  D-Bus method) */
-               if (info->retrieve_all_cb && priv->source)
-                       ignore_limit = info->retrieve_all_cb (priv->source,
-                                                             new_headers_array->len,
-                                                             retrieve_limit);
-       }
-
        /* Copy the headers to a list and free the array */
        new_headers = tny_simple_list_new ();
        for (i=0; i < new_headers_array->len; i++) {
                TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
-               tny_list_append (new_headers, G_OBJECT (header));
+               /* We want the first element to be the most recent
+                  one, that's why we reverse the list */
+               tny_list_prepend (new_headers, G_OBJECT (header));
        }
        g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
        g_ptr_array_free (new_headers_array, FALSE);
@@ -1679,10 +1745,7 @@ inbox_refreshed_cb (TnyFolder *inbox,
                GetMsgInfo *msg_info;
 
                priv->done = 0;
-               if (ignore_limit)
-                       priv->total = tny_list_get_length (new_headers);
-               else
-                       priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
+               priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
 
                iter = tny_list_create_iterator (new_headers);
 
@@ -1702,11 +1765,13 @@ inbox_refreshed_cb (TnyFolder *inbox,
                                                  NULL, msg_info);
 
                        g_object_unref (folder);
+                       g_object_unref (header);
 
                        msg_num++;
                        tny_iterator_next (iter);
                }
                g_object_unref (iter);
+               g_object_unref (new_headers);
 
                /* The mail operation will finish when the last
                   message is retrieved */
@@ -1875,7 +1940,6 @@ modest_mail_operation_update_account (ModestMailOperation *self,
                                      const gchar *account_name,
                                      gboolean poke_all,
                                      gboolean interactive,
-                                     RetrieveAllCallback retrieve_all_cb,
                                      UpdateAccountCallback callback,
                                      gpointer user_data)
 {
@@ -1932,7 +1996,6 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        info->account_name = g_strdup (account_name);
        info->callback = callback;
        info->user_data = user_data;
-       info->retrieve_all_cb = retrieve_all_cb;
 
        /* Set account busy */
        modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
@@ -2086,7 +2149,7 @@ modest_mail_operation_create_folder (ModestMailOperation *self,
                }
        }
 
-       if (!strcmp (name, " ") || strchr (name, '/')) {
+       if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
@@ -2484,6 +2547,69 @@ modest_mail_operation_rename_folder (ModestMailOperation *self,
 /* ******************************************************************* */
 
 void 
+modest_mail_operation_find_msg (ModestMailOperation *self,
+                               TnyFolder *folder,
+                               const gchar *msg_uid,
+                               gboolean progress_feedback,
+                               GetMsgAsyncUserCallback user_callback,
+                               gpointer user_data)
+{
+       GetMsgInfo *helper = NULL;
+       ModestMailOperationPrivate *priv;
+       
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       g_return_if_fail (msg_uid != NULL);
+       
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+       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, NULL, FALSE, NULL, priv->error, user_data);
+               modest_mail_operation_notify_end (self);
+               return;
+       }
+
+       /* Get account and set it into mail_operation */
+       priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
+       
+       /* Check for cached messages */
+       if (progress_feedback) {
+               priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
+       } else {
+               priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
+       }
+       
+       /* Create the helper */
+       helper = g_slice_new0 (GetMsgInfo);
+       helper->header = NULL;
+       helper->mail_op = g_object_ref (self);
+       helper->user_callback = user_callback;
+       helper->user_data = user_data;
+       helper->destroy_notify = NULL;
+       helper->last_total_bytes = 0;
+       helper->sum_total_bytes = 0;
+       helper->total_bytes = 0;
+       helper->more_msgs = NULL;
+
+       modest_mail_operation_notify_start (self);
+       
+       /* notify about the start of the operation */ 
+       ModestMailOperationState *state;
+       state = modest_mail_operation_clone_state (self);
+       state->done = 0;
+       state->total = 0;
+       g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 
+                               0, state, NULL);
+       g_slice_free (ModestMailOperationState, state);
+       
+       tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
+}
+
+void 
 modest_mail_operation_get_msg (ModestMailOperation *self,
                               TnyHeader *header,
                               gboolean progress_feedback,
@@ -2616,6 +2742,8 @@ get_msg_async_cb (TnyFolder *folder,
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
 
+       if (info->header == NULL && msg)
+               info->header = tny_msg_get_header (msg);
 
        /* Call the user callback */
        if (info->user_callback)
@@ -2634,7 +2762,8 @@ get_msg_async_cb (TnyFolder *folder,
                /* Clean */
                if (info->more_msgs)
                        g_object_unref (info->more_msgs);
-               g_object_unref (info->header);
+               if (info->header)
+                       g_object_unref (info->header);
                g_object_unref (info->mail_op);
                g_slice_free (GetMsgInfo, info);
        } else if (info->more_msgs) {
@@ -2799,7 +2928,7 @@ remove_msgs_async_cb (TnyFolder *folder,
                return;
        }
 
-       account = tny_folder_get_account (folder);
+       account = modest_tny_folder_get_account (folder);
        account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
        leave_on_server =
                modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
@@ -2830,6 +2959,7 @@ modest_mail_operation_remove_msgs (ModestMailOperation *self,
        TnyHeader *header = NULL;
        TnyList *remove_headers = NULL;
        TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
+       ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
 
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_LIST (headers));
@@ -2841,52 +2971,67 @@ modest_mail_operation_remove_msgs (ModestMailOperation *self,
                g_warning ("%s: list of headers is empty\n", __FUNCTION__);
                goto cleanup; /* nothing to do */
        }
-       
+
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
-       remove_headers = g_object_ref(headers);
 
        /* Get folder from first header and sync it */
-       iter = tny_list_create_iterator (headers);      
+       iter = tny_list_create_iterator (headers);
        header = TNY_HEADER (tny_iterator_get_current (iter));
+       g_object_unref (iter);
 
-       folder = tny_header_get_folder (header);        
+       folder = tny_header_get_folder (header);
        if (!TNY_IS_FOLDER(folder)) {
                g_warning ("%s: could not get folder for header\n", __FUNCTION__);
                goto cleanup;
        }
 
-       /* Don't remove messages that are being sent */
+       /* Use the merged folder if we're removing messages from outbox */
        if (modest_tny_folder_is_local_folder (folder)) {
+               ModestTnyLocalFoldersAccount *local_account;
+
+               local_account = (ModestTnyLocalFoldersAccount *)
+                       modest_tny_account_store_get_local_folders_account (accstore);
                folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
+               if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
+                       g_object_unref (folder);
+                       folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
+               }
+               g_object_unref (local_account);
        }
+
        if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
-               TnyTransportAccount *traccount = NULL;
-               ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
-               traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
-               if (traccount) {
-                       ModestTnySendQueueStatus status;
-                       ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
-
-                       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)) {
+               TnyIterator *headers_iter = tny_list_create_iterator (headers);
+
+               while (!tny_iterator_is_done (headers_iter)) {
+                       TnyTransportAccount *traccount = NULL;
+                       TnyHeader *hdr = NULL;
+
+                       hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
+                       traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
+                                                                                                      header);
+                       if (traccount) {
+                               ModestTnySendQueueStatus status;
+                               ModestTnySendQueue *send_queue;
+
+                               send_queue = modest_runtime_get_send_queue(traccount, TRUE);
+                               if (TNY_IS_SEND_QUEUE (send_queue)) {
                                        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) {
+                                               if (G_UNLIKELY (remove_headers == NULL))
+                                                       remove_headers = tny_simple_list_new ();
                                                tny_list_append(remove_headers, G_OBJECT(hdr));
                                        }
-                                       g_object_unref(hdr);
                                        g_free(msg_id);
-                                       tny_iterator_next(iter);
                                }
-                               g_object_unref(iter);
+                               g_object_unref(traccount);
                        }
-                       g_object_unref(traccount);
+                       g_object_unref(hdr);
+                       tny_iterator_next (headers_iter);
                }
+               g_object_unref(headers_iter);
        }
 
        /* Get account and set it into mail_operation */
@@ -2894,6 +3039,9 @@ modest_mail_operation_remove_msgs (ModestMailOperation *self,
        priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
        priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
 
+       if (!remove_headers)
+               remove_headers = g_object_ref (headers);
+
        /* remove message from folder */
        modest_mail_operation_notify_start (self);
        tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb, 
@@ -2904,8 +3052,6 @@ cleanup:
                g_object_unref (remove_headers);
        if (header)
                g_object_unref (header);
-       if (iter)
-               g_object_unref (iter);
        if (folder)
                g_object_unref (folder);
 }