* src/modest-account-mgr-helpers.c:
[modest] / src / modest-mail-operation.c
index 5836ff5..b441d2a 100644 (file)
@@ -135,7 +135,7 @@ struct _ModestMailOperationPrivate {
 typedef struct {
        GetMsgAsyncUserCallback user_callback;
        TnyHeader *header;
-       TnyIterator *iter;
+       TnyIterator *more_msgs;
        gpointer user_data;
        ModestMailOperation *mail_op;
        GDestroyNotify destroy_notify;
@@ -154,6 +154,7 @@ typedef struct _XFerMsgsAsyncHelper
 {
        ModestMailOperation *mail_op;
        TnyList *headers;
+       TnyIterator *more_msgs;
        TnyFolder *dest_folder;
        XferMsgsAsyncUserCallback user_callback;        
        gboolean delete;
@@ -488,11 +489,6 @@ modest_mail_operation_cancel (ModestMailOperation *self)
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
-       /* Note that if we call cancel with an already canceled mail
-          operation the progress changed signal won't be emitted */
-       if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
-               return FALSE;
-
        /* Set new status */
        priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
        
@@ -740,11 +736,8 @@ modest_mail_operation_create_msg (ModestMailOperation *self,
                                  ModestMailOperationCreateMsgCallback callback,
                                  gpointer userdata)
 {
-       ModestMailOperationPrivate *priv;
        CreateMsgInfo *info = NULL;
 
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
-
        info = g_slice_new0 (CreateMsgInfo);
        info->mail_op = g_object_ref (self);
 
@@ -1230,7 +1223,7 @@ inbox_refreshed_cb (TnyFolder *inbox,
        ModestAccountRetrieveType retrieve_type;
        TnyList *new_headers = NULL;
        gboolean headers_only, ignore_limit;
-       TnyTransportAccount *transport_account;
+       TnyTransportAccount *transport_account = NULL;
 
        info = (UpdateAccountInfo *) user_data;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
@@ -1271,6 +1264,8 @@ inbox_refreshed_cb (TnyFolder *inbox,
 
        /* Update the last updated key, even if we don't have to get new headers */
        modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
+       if (!canceled && !err) 
+               modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
        
        if (new_headers_array->len == 0)
                goto send_mail;
@@ -1352,12 +1347,18 @@ inbox_refreshed_cb (TnyFolder *inbox,
                guint num_messages;
 
                send_queue = modest_runtime_get_send_queue (transport_account);
+               g_object_unref (transport_account);
 
                /* Get outbox folder */
                outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
-               num_messages = tny_folder_get_all_count (outbox);
-               g_object_unref (outbox);
-
+               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) {
                        /* Send mails */
                        g_object_unref (priv->account);
@@ -1368,7 +1369,7 @@ inbox_refreshed_cb (TnyFolder *inbox,
                        /* Try to send */
                        tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
                }
-       } 
+       }
 
        /* Check if the operation was a success */
        if (!priv->error)
@@ -1492,7 +1493,6 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        UpdateAccountInfo *info = NULL;
        ModestMailOperationPrivate *priv = NULL;
        ModestTnyAccountStore *account_store = NULL;
-       TnyStoreAccount *store_account = NULL;
        TnyList *folders;
        ModestMailOperationState *state;
 
@@ -1505,11 +1505,10 @@ modest_mail_operation_update_account (ModestMailOperation *self,
 
        /* Get the store account */
        account_store = modest_runtime_get_account_store ();
-       store_account = (TnyStoreAccount *)
+       priv->account =
                modest_tny_account_store_get_server_account (account_store,
                                                             account_name,
                                                             TNY_ACCOUNT_TYPE_STORE);
-       priv->account = g_object_ref (store_account);
 
        /* Create the helper object */
        info = g_slice_new0 (UpdateAccountInfo);
@@ -1537,7 +1536,7 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        
        /* Get all folders and continue in the callback */ 
        folders = tny_simple_list_new ();
-       tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
+       tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
                                            folders, NULL,
                                            recurse_folders_async_cb, 
                                            NULL, info);
@@ -1704,7 +1703,6 @@ modest_mail_operation_remove_folder (ModestMailOperation *self,
                                     TnyFolder           *folder,
                                     gboolean             remove_to_trash)
 {
-       TnyAccount *account;
        ModestMailOperationPrivate *priv;
        ModestTnyFolderRules rules;
 
@@ -1725,14 +1723,13 @@ modest_mail_operation_remove_folder (ModestMailOperation *self,
        }
 
        /* Get the account */
-       account = modest_tny_folder_get_account (folder);
-       priv->account = g_object_ref(account);
+       priv->account = modest_tny_folder_get_account (folder);
        priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
 
        /* Delete folder or move to trash */
        if (remove_to_trash) {
                TnyFolder *trash_folder = NULL;
-               trash_folder = modest_tny_account_get_special_folder (account,
+               trash_folder = modest_tny_account_get_special_folder (priv->account,
                                                                      TNY_FOLDER_TYPE_TRASH);
                /* TODO: error_handling */
                if (trash_folder) {
@@ -1758,7 +1755,6 @@ modest_mail_operation_remove_folder (ModestMailOperation *self,
                } else
                        g_warning ("%s: could not get parent folder", __FUNCTION__);
        }
-       g_object_unref (G_OBJECT (account));
 
  end:
        /* Notify about operation end */
@@ -2150,15 +2146,18 @@ get_msg_async_cb (TnyFolder *folder,
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
        priv->done++;
 
-       if (info->iter) {
-               tny_iterator_next (info->iter);
-               finished = (tny_iterator_is_done (info->iter));
+       if (info->more_msgs) {
+               tny_iterator_next (info->more_msgs);
+               finished = (tny_iterator_is_done (info->more_msgs));
        } else {
                finished = (priv->done == priv->total) ? TRUE : FALSE;
        }
 
-       /* Check errors */
-       if (canceled || err) {
+       /* If canceled by the user, ignore the error given by Tinymail */
+       if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
+               canceled = TRUE;
+               finished = TRUE;
+       } else if (canceled || err) {
                priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
                if (err) {
                        priv->error = g_error_copy ((const GError *) err);
@@ -2172,9 +2171,6 @@ get_msg_async_cb (TnyFolder *folder,
        } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
                /* Set the success status before calling the user callback */
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
-       } else if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
-               canceled = TRUE;
-               finished = TRUE;
        }
 
 
@@ -2193,13 +2189,13 @@ get_msg_async_cb (TnyFolder *folder,
                modest_mail_operation_notify_end (info->mail_op);
 
                /* Clean */
-               if (info->iter)
-                       g_object_unref (info->iter);
+               if (info->more_msgs)
+                       g_object_unref (info->more_msgs);
                g_object_unref (info->header);
                g_object_unref (info->mail_op);
                g_slice_free (GetMsgInfo, info);
-       } else if (info->iter) {
-               TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->iter));
+       } else if (info->more_msgs) {
+               TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
                TnyFolder *folder = tny_header_get_folder (header);
 
                g_object_unref (info->header);
@@ -2271,7 +2267,7 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self,
                msg_info = g_slice_new0 (GetMsgInfo);
                msg_info->mail_op = g_object_ref (self);
                msg_info->header = g_object_ref (header);
-               msg_info->iter = g_object_ref (iter);
+               msg_info->more_msgs = g_object_ref (iter);
                msg_info->user_callback = user_callback;
                msg_info->user_data = user_data;
                msg_info->destroy_notify = notify;
@@ -2567,8 +2563,7 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer u
        XFerMsgsAsyncHelper *helper;
        ModestMailOperation *self;
        ModestMailOperationPrivate *priv;
-       TnyIterator *iter = NULL;
-       TnyHeader *header = NULL;
+       gboolean finished = TRUE;
 
        helper = (XFerMsgsAsyncHelper *) user_data;
        self = helper->mail_op;
@@ -2585,56 +2580,66 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer u
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             _("Error trying to refresh the contents of %s"),
                             tny_folder_get_name (folder));
-       } else {
-               priv->done = 1;
-               priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+       } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
+               if (helper->more_msgs) {
+                       /* We'll transfer the next message in the list */
+                       tny_iterator_next (helper->more_msgs);
+                       if (!tny_iterator_is_done (helper->more_msgs)) {
+                               GObject *next_header;
+                               g_object_unref (helper->headers);
+                               helper->headers = tny_simple_list_new ();
+                               next_header = tny_iterator_get_current (helper->more_msgs);
+                               tny_list_append (helper->headers, next_header);
+                               g_object_unref (next_header);
+                               finished = FALSE;
+                       }
+               }
 
-               /* Update folder counts */
-               tny_folder_poke_status (folder);                
-               tny_folder_poke_status (helper->dest_folder);           
+               if (finished) {
+                       priv->done = 1;
+                       priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+               }
        }
 
-       
-       /* Mark headers as deleted and seen */
-       if ((helper->delete) && 
-           (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)) {
-               iter = tny_list_create_iterator (helper->headers);
-               while (!tny_iterator_is_done (iter)) {
-                       header = TNY_HEADER (tny_iterator_get_current (iter));
-                       tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
-                       tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
-                       g_object_unref (header);
+       if (finished) {
 
-                       tny_iterator_next (iter);
-               }
-       }
-               
+               /* 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);
+               /* 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 */
+               /* 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 */
-       }
+                       /* no gdk_threads_enter (), CHECKED */
+                       helper->user_callback (self, helper->user_data);
+                       /* no gdk_threads_leave (), CHECKED */
+               }
 
-       /* Free */
-       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);
-       if (folder)
-               g_object_unref (folder);
-       if (iter)
-               g_object_unref (iter);
-       g_slice_free (XFerMsgsAsyncHelper, helper);
+               /* 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);
+       } else {
+               /* Transfer more messages */
+               tny_folder_transfer_msgs_async (folder,
+                                               helper->headers,
+                                               helper->dest_folder,
+                                               helper->delete,
+                                               transfer_msgs_cb,
+                                               transfer_msgs_status_cb,
+                                               helper);
+       }
 }
 
 static guint
@@ -2684,6 +2689,8 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
        XFerMsgsAsyncHelper *helper = NULL;
        TnyHeader *header = NULL;
        ModestTnyFolderRules rules = 0;
+       TnyAccount *dst_account = NULL;
+       gboolean leave_on_server;
 
        g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (headers && TNY_IS_LIST (headers));
@@ -2746,7 +2753,6 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
        helper = g_slice_new0 (XFerMsgsAsyncHelper);
        helper->mail_op = g_object_ref(self);
        helper->dest_folder = g_object_ref(folder);
-       helper->headers = g_object_ref(headers);
        helper->user_callback = user_callback;
        helper->user_data = user_data;
        helper->delete = delete_original;
@@ -2756,16 +2762,53 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
 
        /* Get account and set it into mail_operation */
        priv->account = modest_tny_folder_get_account (src_folder);
+       dst_account = modest_tny_folder_get_account (folder);
+
+       if (priv->account == dst_account) {
+               /* Transfer all messages at once using the fast
+                * method. Note that depending on the server this
+                * might not be that fast, and might not be
+                * user-cancellable either */
+               helper->headers = g_object_ref (headers);
+               helper->more_msgs = NULL;
+       } else {
+               /* Transfer messages one by one so the user can cancel
+                * the operation */
+               GObject *hdr;
+               helper->headers = tny_simple_list_new ();
+               helper->more_msgs = tny_list_create_iterator (headers);
+               hdr = tny_iterator_get_current (helper->more_msgs);
+               tny_list_append (helper->headers, hdr);
+               g_object_unref (hdr);
+       }
+
+       /* If leave_on_server is set to TRUE then don't use
+          delete_original, we always pass FALSE. This is because
+          otherwise tinymail will try to sync the source folder and
+          this could cause an error if we're offline while
+          transferring an already downloaded message from a POP
+          account */
+        if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) == 
+           MODEST_PROTOCOL_STORE_POP) {
+               const gchar *account_name;
+
+               account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
+               leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
+                                                                         account_name);
+       } else {
+               leave_on_server = FALSE;
+       }
 
-       /* Transfer messages */
        modest_mail_operation_notify_start (self);
        tny_folder_transfer_msgs_async (src_folder, 
-                                       headers, 
+                                       helper->headers, 
                                        folder, 
-                                       delete_original, 
+                                       (leave_on_server) ? FALSE : delete_original, 
                                        transfer_msgs_cb, 
                                        transfer_msgs_status_cb,
                                        helper);
+       g_object_unref (src_folder);
+       g_object_unref (dst_account);
 }
 
 
@@ -2785,6 +2828,19 @@ on_refresh_folder (TnyFolder   *folder,
 
        g_return_if_fail(priv!=NULL);
 
+       /* If the folder is remote, set the "Last updated" value */
+       if (modest_tny_folder_is_remote_folder (folder)) {
+               TnyAccount *account = modest_tny_folder_get_account (folder);
+               ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
+               const gchar *name;
+               name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
+               modest_account_mgr_set_last_updated (mgr, tny_account_get_id (account), time (NULL));
+               if (!cancelled && !error)
+                       modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (account), TRUE);
+               modest_account_mgr_set_account_busy (mgr, name, FALSE);
+               g_object_unref (account);
+       }
+
        if (error) {
                priv->error = g_error_copy (error);
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
@@ -2877,6 +2933,12 @@ modest_mail_operation_refresh_folder  (ModestMailOperation *self,
        /* Refresh the folder. TODO: tinymail could issue a status
           updates before the callback call then this could happen. We
           must review the design */
+       if (modest_tny_folder_is_remote_folder (folder)) {
+               /* If the folder is remote, mark its account as busy */
+               const gchar *name;
+               name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
+               modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), name, TRUE);
+       }
        modest_mail_operation_notify_start (self);
        
        /* notify that the operation was started */
@@ -2886,6 +2948,8 @@ modest_mail_operation_refresh_folder  (ModestMailOperation *self,
        state->total = 0;
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 
                        0, state, NULL);
+
+       /* FIXME: we're leaking the state here, or? valgrind thinks so */
        
        tny_folder_refresh_async (folder,
                                  on_refresh_folder,