* Review dimming rules to detect when modest is sedning mails.
[modest] / src / modest-mail-operation.c
index 4519119..6d8e4e1 100644 (file)
@@ -35,6 +35,9 @@
 #include <tny-folder-store-query.h>
 #include <tny-camel-stream.h>
 #include <tny-camel-pop-store-account.h>
+#include <tny-camel-pop-folder.h>
+#include <tny-camel-imap-folder.h>
+#include <tny-camel-mem-stream.h>
 #include <tny-simple-list.h>
 #include <tny-send-queue.h>
 #include <tny-status.h>
@@ -48,6 +51,7 @@
 #include "modest-text-utils.h"
 #include "modest-tny-msg.h"
 #include "modest-tny-folder.h"
+#include "modest-tny-account-store.h"
 #include "modest-tny-platform-factory.h"
 #include "modest-marshal.h"
 #include "modest-error.h"
 
 #define KB 1024
 
+/* 
+ * Remove all these #ifdef stuff when the tinymail's idle calls become
+ * locked
+ */
+#define TINYMAIL_IDLES_NOT_LOCKED_YET 1
+
 /* 'private'/'protected' functions */
 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
 static void modest_mail_operation_init       (ModestMailOperation *obj);
@@ -63,7 +73,7 @@ static void modest_mail_operation_finalize   (GObject *obj);
 static void     get_msg_cb (TnyFolder *folder, 
                            gboolean cancelled, 
                            TnyMsg *msg, 
-                           GError **err, 
+                           GError *rr, 
                            gpointer user_data);
 
 static void     get_msg_status_cb (GObject *obj,
@@ -72,8 +82,6 @@ static void     get_msg_status_cb (GObject *obj,
 
 static void     modest_mail_operation_notify_end (ModestMailOperation *self);
 
-static gboolean did_a_cancel = FALSE;
-
 enum _ModestMailOperationSignals 
 {
        PROGRESS_CHANGED_SIGNAL,
@@ -105,6 +113,7 @@ struct _ModestMailOperationPrivate {
 
 typedef struct _GetMsgAsyncHelper {    
        ModestMailOperation *mail_op;
+       TnyHeader *header;
        GetMsgAsyncUserCallback user_callback;  
        gpointer user_data;
 } GetMsgAsyncHelper;
@@ -121,9 +130,48 @@ typedef struct _XFerMsgAsyncHelper
        TnyList *headers;
        TnyFolder *dest_folder;
        XferMsgsAsynUserCallback user_callback; 
+       gboolean delete;
        gpointer user_data;
 } XFerMsgAsyncHelper;
 
+typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
+                                                     TnyMsg *msg,
+                                                     gpointer userdata);
+
+static void          modest_mail_operation_create_msg (ModestMailOperation *self,
+                                                      const gchar *from, const gchar *to,
+                                                      const gchar *cc, const gchar *bcc,
+                                                      const gchar *subject, const gchar *plain_body,
+                                                      const gchar *html_body, const GList *attachments_list,
+                                                      TnyHeaderFlags priority_flags,
+                                                      ModestMailOperationCreateMsgCallback callback,
+                                                      gpointer userdata);
+
+static gboolean      idle_notify_queue (gpointer data);
+typedef struct
+{
+       ModestMailOperation *mail_op;
+       gchar *from;
+       gchar *to;
+       gchar *cc;
+       gchar *bcc;
+       gchar *subject;
+       gchar *plain_body;
+       gchar *html_body;
+       GList *attachments_list;
+       TnyHeaderFlags priority_flags;
+       ModestMailOperationCreateMsgCallback callback;
+       gpointer userdata;
+} CreateMsgInfo;
+
+typedef struct
+{
+       ModestMailOperation *mail_op;
+       TnyMsg *msg;
+       ModestMailOperationCreateMsgCallback callback;
+       gpointer userdata;
+} CreateMsgIdleInfo;
+
 /* globals */
 static GObjectClass *parent_class = NULL;
 
@@ -257,6 +305,7 @@ modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation
        
        g_return_val_if_fail (error_handler != NULL, obj);
        priv->error_checking = error_handler;
+       priv->error_checking_user_data = user_data;
 
        return obj;
 }
@@ -352,30 +401,27 @@ gboolean
 modest_mail_operation_cancel (ModestMailOperation *self)
 {
        ModestMailOperationPrivate *priv;
+       gboolean canceled = FALSE;
 
-       if (!MODEST_IS_MAIL_OPERATION (self)) {
-               g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
-               return FALSE;
-       }
+       g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
-       if (!priv) {
-               g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
-               return FALSE;
-       }
 
-       /* Notify about operation end */
-       modest_mail_operation_notify_end (self);
-
-       did_a_cancel = TRUE;
+       /* 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;
        
-       modest_mail_operation_queue_cancel_all (modest_runtime_get_mail_operation_queue());
+       /* Cancel the mail operation. We need to wrap it between this
+          start/stop operations to allow following calls to the
+          account */
+       g_return_val_if_fail (priv->account, FALSE);
+       tny_account_cancel (priv->account);
 
-       
-       return TRUE;
+       return canceled;
 }
 
 guint 
@@ -477,6 +523,8 @@ modest_mail_operation_clone_state (ModestMailOperation *self)
        state->done = priv->done;
        state->total = priv->total;
        state->finished = modest_mail_operation_is_finished (self);
+       state->bytes_done = 0;
+       state->bytes_total = 0;
 
        return state;
 }
@@ -501,17 +549,226 @@ modest_mail_operation_send_mail (ModestMailOperation *self,
 
        /* Get account and set it into mail_operation */
        priv->account = g_object_ref (transport_account);
+       priv->done = 1;
+       priv->total = 1;
 
        send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
        if (!TNY_IS_SEND_QUEUE(send_queue)) {
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             "modest: could not find send queue for account\n");
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+
+       } else {
+               /* TODO: connect to the msg-sent in order to know when
+                  the mail operation is finished */
+
+/*             tny_send_queue_add (send_queue, msg, &(priv->error)); */
+               modest_tny_send_queue_add (MODEST_TNY_SEND_QUEUE(send_queue), 
+                                          msg, 
+                                          &(priv->error));
+
+               /* TODO: we're setting always success, do the check in
+                  the handler */
+               priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+       }
+
+       if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS)
+               modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
+
+       /* TODO: do this in the handler of the "msg-sent"
+          signal.Notify about operation end */
+       modest_mail_operation_notify_end (self);
+}
+
+static gboolean
+idle_create_msg_cb (gpointer idle_data)
+{
+       CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
+
+       /* This is a GDK lock because we are an idle callback and
+        * info->callback can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED */
+       info->callback (info->mail_op, info->msg, info->userdata);
+       gdk_threads_leave (); /* CHECKED */
+
+       g_object_unref (info->mail_op);
+       if (info->msg)
+               g_object_unref (info->msg);
+       g_slice_free (CreateMsgIdleInfo, info);
+
+       return FALSE;
+}
+
+static gpointer 
+create_msg_thread (gpointer thread_data)
+{
+       CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
+       TnyMsg *new_msg = NULL;
+       ModestMailOperationPrivate *priv;
+
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
+       if (info->html_body == NULL) {
+               new_msg = modest_tny_msg_new (info->to, info->from, info->cc, 
+                                             info->bcc, info->subject, info->plain_body, 
+                                             info->attachments_list); /* FIXME: attachments */
        } else {
-               tny_send_queue_add (send_queue, msg, &(priv->error));
+               new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
+                                                        info->bcc, info->subject, info->html_body,
+                                                        info->plain_body, info->attachments_list);
        }
 
-       /* Notify about operation end */
+       if (new_msg) {
+               TnyHeader *header;
+               TnyHeaderFlags flags = 0;
+
+               /* Set priority flags in message */
+               header = tny_msg_get_header (new_msg);
+               if (info->priority_flags != 0)
+                       flags |= info->priority_flags;
+
+               /* Set attachment flags in message */
+               if (info->attachments_list != NULL)
+                       flags |= TNY_HEADER_FLAG_ATTACHMENTS;
+
+               tny_header_set_flags (header, flags);
+               g_object_unref (G_OBJECT(header));
+       } else {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
+                            "modest: failed to create a new msg\n");
+       }
+
+
+       g_free (info->to);
+       g_free (info->from);
+       g_free (info->cc);
+       g_free (info->bcc);
+       g_free (info->plain_body);
+       g_free (info->html_body);
+       g_free (info->subject);
+       g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
+       g_list_free (info->attachments_list);
+
+       if (info->callback) {
+               CreateMsgIdleInfo *idle_info;
+               idle_info = g_slice_new0 (CreateMsgIdleInfo);
+               idle_info->mail_op = info->mail_op;
+               g_object_ref (info->mail_op);
+               idle_info->msg = new_msg;
+               if (new_msg)
+                       g_object_ref (new_msg);
+               idle_info->callback = info->callback;
+               idle_info->userdata = info->userdata;
+               g_idle_add (idle_create_msg_cb, idle_info);
+       } else {
+               g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
+       }
+
+       g_object_unref (info->mail_op);
+       g_slice_free (CreateMsgInfo, info);
+       return NULL;
+}
+
+void
+modest_mail_operation_create_msg (ModestMailOperation *self,
+                                 const gchar *from, const gchar *to,
+                                 const gchar *cc, const gchar *bcc,
+                                 const gchar *subject, const gchar *plain_body,
+                                 const gchar *html_body,
+                                 const GList *attachments_list,
+                                 TnyHeaderFlags priority_flags,
+                                 ModestMailOperationCreateMsgCallback callback,
+                                 gpointer userdata)
+{
+       CreateMsgInfo *info = NULL;
+
+       info = g_slice_new0 (CreateMsgInfo);
+       info->mail_op = self;
+       g_object_ref (self);
+
+       info->from = g_strdup (from);
+       info->to = g_strdup (to);
+       info->cc = g_strdup (cc);
+       info->bcc  = g_strdup (bcc);
+       info->subject = g_strdup (subject);
+       info->plain_body = g_strdup (plain_body);
+       info->html_body = g_strdup (html_body);
+       info->attachments_list = g_list_copy ((GList *) attachments_list);
+       g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
+       info->priority_flags = priority_flags;
+
+       info->callback = callback;
+       info->userdata = userdata;
+
+       g_thread_create (create_msg_thread, info, FALSE, NULL);
+}
+
+typedef struct
+{
+       TnyTransportAccount *transport_account;
+       TnyMsg *draft_msg;
+} SendNewMailInfo;
+
+static void
+modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
+                                       TnyMsg *msg,
+                                       gpointer userdata)
+{
+       SendNewMailInfo *info = (SendNewMailInfo *) userdata;
+       TnyFolder *draft_folder = NULL;
+       TnyFolder *outbox_folder = NULL;
+       TnyHeader *header;
+       GError *err = NULL;
+
+       if (!msg) {
+               goto end;
+       }
+
+       /* Call mail operation */
+       modest_mail_operation_send_mail (self, info->transport_account, msg);
+
+       /* Remove old mail from its source folder */
+       draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
+       outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_OUTBOX);
+       if (info->draft_msg != NULL) {
+               TnyFolder *folder = NULL;
+               TnyFolder *src_folder = NULL;
+               TnyFolderType folder_type;              
+               folder = tny_msg_get_folder (info->draft_msg);          
+               if (folder == NULL) goto end;
+               folder_type = modest_tny_folder_guess_folder_type (folder);
+               if (folder_type == TNY_FOLDER_TYPE_OUTBOX) 
+                       src_folder = outbox_folder;
+               else 
+                       src_folder = draft_folder;
+
+               /* Note: This can fail (with a warning) if the message is not really already in a folder,
+                * because this function requires it to have a UID. */          
+               header = tny_msg_get_header (info->draft_msg);
+               tny_folder_remove_msg (src_folder, header, NULL);
+
+               tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
+/*             tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);  /\* expunge *\/ */
+               
+               g_object_unref (header);
+               g_object_unref (folder);
+       }
+
+end:
+       if (err != NULL)
+               g_error_free(err);      
+       if (info->draft_msg)
+               g_object_unref (info->draft_msg);
+       if (draft_folder)
+               g_object_unref (draft_folder);
+       if (outbox_folder)
+               g_object_unref (outbox_folder);
+       if (info->transport_account)
+               g_object_unref (info->transport_account);
+       g_slice_free (SendNewMailInfo, info);
        modest_mail_operation_notify_end (self);
 }
 
@@ -526,19 +783,14 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self,
                                     const GList *attachments_list,
                                     TnyHeaderFlags priority_flags)
 {
-       TnyMsg *new_msg = NULL;
-       TnyFolder *folder = NULL;
-       TnyHeader *header = NULL;
        ModestMailOperationPrivate *priv = NULL;
+       SendNewMailInfo *info;
 
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       /* Get account and set it into mail_operation */
-       priv->account = g_object_ref (transport_account);
-
        /* Check parametters */
        if (to == NULL) {
                /* Set status failed and set an error */
@@ -548,109 +800,136 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self,
                             _("Error trying to send a mail. You need to set at least one recipient"));
                return;
        }
+       info = g_slice_new0 (SendNewMailInfo);
+       info->transport_account = transport_account;
+       if (transport_account)
+               g_object_ref (transport_account);
+       info->draft_msg = draft_msg;
+       if (draft_msg)
+               g_object_ref (draft_msg);
+       modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
+                                         attachments_list, priority_flags,
+                                         modest_mail_operation_send_new_mail_cb, info);
 
-       if (html_body == NULL) {
-               new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
-       } else {
-               new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
-       }
-       if (!new_msg) {
-               g_printerr ("modest: failed to create a new msg\n");
-               return;
-       }
-
-       /* Set priority flags in message */
-       header = tny_msg_get_header (new_msg);
-       if (priority_flags != 0)
-               tny_header_set_flags (header, priority_flags);
-
-       /* Call mail operation */
-       modest_mail_operation_send_mail (self, transport_account, new_msg);
-
-       folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
-       if (folder) {
-               if (draft_msg != NULL) {
-                       header = tny_msg_get_header (draft_msg);
-                       /* Note: This can fail (with a warning) if the message is not really already in a folder,
-                        * because this function requires it to have a UID. */
-                       tny_folder_remove_msg (folder, header, NULL);
-                       g_object_unref (header);
-               }
-       }
-
-       /* Free */
-       g_object_unref (G_OBJECT (new_msg));
 }
 
-void
-modest_mail_operation_save_to_drafts (ModestMailOperation *self,
-                                     TnyTransportAccount *transport_account,
-                                     TnyMsg *draft_msg,
-                                     const gchar *from,  const gchar *to,
-                                     const gchar *cc,  const gchar *bcc,
-                                     const gchar *subject, const gchar *plain_body,
-                                     const gchar *html_body,
-                                     const GList *attachments_list,
-                                     TnyHeaderFlags priority_flags)
+typedef struct
 {
-       TnyMsg *msg = NULL;
+       TnyTransportAccount *transport_account;
+       TnyMsg *draft_msg;
+       ModestMsgEditWindow *edit_window;
+} SaveToDraftsInfo;
+
+static void
+modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
+                                        TnyMsg *msg,
+                                        gpointer userdata)
+{
+       TnyFolder *src_folder = NULL;
        TnyFolder *folder = NULL;
        TnyHeader *header = NULL;
        ModestMailOperationPrivate *priv = NULL;
-
-       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
-       g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
+       SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
-
-       /* Get account and set it into mail_operation */
-       priv->account = g_object_ref (transport_account);
-
-       if (html_body == NULL) {
-               msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
-       } else {
-               msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
-       }
        if (!msg) {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
                             "modest: failed to create a new msg\n");
                goto end;
        }
 
-       /* add priority flags */
-       header = tny_msg_get_header (msg);
-       tny_header_set_flags (header, priority_flags);
-
-       folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
+       folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
        if (!folder) {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             "modest: failed to create a new msg\n");
                goto end;
        }
 
-       if (draft_msg != NULL) {
-               header = tny_msg_get_header (draft_msg);
+       if (!priv->error)
+               tny_folder_add_msg (folder, msg, &(priv->error));
+
+       if ((!priv->error) && (info->draft_msg != NULL)) {
+               header = tny_msg_get_header (info->draft_msg);
+               src_folder = tny_header_get_folder (header); 
+
                /* Remove the old draft expunging it */
-               tny_folder_remove_msg (folder, header, NULL);
-               tny_folder_sync (folder, TRUE, NULL);
+               tny_folder_remove_msg (src_folder, header, NULL);
+/*             tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED); */
+/*             tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN); */
+
+               tny_folder_sync (folder, TRUE, &(priv->error)); /* FALSE --> don't expunge */
+               tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);  /* expunge */
+
                g_object_unref (header);
        }
        
-       tny_folder_add_msg (folder, msg, &(priv->error));
-       if (priv->error)
-               goto end;
+       if (!priv->error)
+               priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+       else
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+
+       if (info->edit_window)
+               modest_msg_edit_window_set_draft (info->edit_window, msg);
+
 
 end:
-       if (msg)
-               g_object_unref (G_OBJECT(msg));
        if (folder)
                g_object_unref (G_OBJECT(folder));
+       if (src_folder)
+               g_object_unref (G_OBJECT(src_folder));
+       if (info->edit_window)
+               g_object_unref (G_OBJECT(info->edit_window));
+       if (info->draft_msg)
+               g_object_unref (G_OBJECT (info->draft_msg));
+       if (info->transport_account)
+               g_object_unref (G_OBJECT(info->transport_account));
+       g_slice_free (SaveToDraftsInfo, info);
 
        modest_mail_operation_notify_end (self);
 }
 
+void
+modest_mail_operation_save_to_drafts (ModestMailOperation *self,
+                                     TnyTransportAccount *transport_account,
+                                     TnyMsg *draft_msg,
+                                     ModestMsgEditWindow *edit_window,
+                                     const gchar *from,  const gchar *to,
+                                     const gchar *cc,  const gchar *bcc,
+                                     const gchar *subject, const gchar *plain_body,
+                                     const gchar *html_body,
+                                     const GList *attachments_list,
+                                     TnyHeaderFlags priority_flags)
+{
+       ModestMailOperationPrivate *priv = NULL;
+       SaveToDraftsInfo *info = NULL;
+
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
+
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
+
+       /* Get account and set it into mail_operation */
+       priv->account = g_object_ref (transport_account);
+
+       info = g_slice_new0 (SaveToDraftsInfo);
+       info->transport_account = g_object_ref (transport_account);
+       info->draft_msg = draft_msg;
+       if (draft_msg)
+               g_object_ref (draft_msg);
+       info->edit_window = edit_window;
+       if (edit_window)
+               g_object_ref (edit_window);
+
+       modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
+                                         attachments_list, priority_flags,
+                                         modest_mail_operation_save_to_drafts_cb, info);
+
+}
+
 typedef struct 
 {
        ModestMailOperation *mail_op;
@@ -660,8 +939,20 @@ typedef struct
        gint retrieve_limit;
        gchar *retrieve_type;
        gchar *account_name;
+       UpdateAccountCallback callback;
+       gpointer user_data;
+       gint new_headers;
 } UpdateAccountInfo;
 
+typedef struct
+{
+       ModestMailOperation *mail_op;
+       TnyMimePart *mime_part;
+       gssize size;
+       GetMimePartSizeCallback callback;
+       gpointer userdata;
+} GetMimePartSizeInfo;
+
 /***** I N T E R N A L    F O L D E R    O B S E R V E R *****/
 /* We use this folder observer to track the headers that have been
  * added to a folder */
@@ -685,9 +976,6 @@ G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
 static void
 foreach_add_item (gpointer header, gpointer user_data)
 {
-       /* printf("DEBUG: %s: header subject=%s\n", 
-        * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
-        */
        tny_list_prepend (TNY_LIST (user_data), 
                          g_object_ref (G_OBJECT (header)));
 }
@@ -709,10 +997,6 @@ internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *chang
                list = tny_simple_list_new ();
                tny_folder_change_get_added_headers (change, list);
 
-               /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n", 
-                *      __FUNCTION__, tny_list_get_length(list));
-                */
-                
                /* Add them to the folder observer */
                tny_list_foreach (list, foreach_add_item, 
                                  derived->new_headers);
@@ -765,10 +1049,11 @@ recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all
        while (!tny_iterator_is_done (iter)) {
 
                TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
-
-               tny_list_prepend (all_folders, G_OBJECT (folder));
-               recurse_folders (folder, query, all_folders);    
-               g_object_unref (G_OBJECT (folder));
+               if (folder) {
+                       tny_list_prepend (all_folders, G_OBJECT (folder));
+                       recurse_folders (folder, query, all_folders);    
+                       g_object_unref (G_OBJECT (folder));
+               }
 
                tny_iterator_next (iter);
        }
@@ -787,7 +1072,14 @@ idle_notify_progress (gpointer data)
        ModestMailOperationState *state;
 
        state = modest_mail_operation_clone_state (mail_op);
+
+       /* This is a GDK lock because we are an idle callback and
+        * the handlers of this signal can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED */
        g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
+       gdk_threads_leave (); /* CHECKED */
+
        g_slice_free (ModestMailOperationState, state);
        
        return TRUE;
@@ -805,7 +1097,12 @@ idle_notify_progress_once (gpointer data)
 
        pair = (ModestPair *) data;
 
+       /* This is a GDK lock because we are an idle callback and
+        * the handlers of this signal can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED */
        g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
+       gdk_threads_leave (); /* CHECKED */
 
        /* Free the state and the reference to the mail operation */
        g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
@@ -815,17 +1112,15 @@ idle_notify_progress_once (gpointer data)
 }
 
 /* 
- * Used by update_account_thread to notify the queue from the main
+ * Used to notify the queue from the main
  * loop. We call it inside an idle call to achieve that
  */
 static gboolean
-notify_update_account_queue (gpointer data)
+idle_notify_queue (gpointer data)
 {
        ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
-       ModestMailOperationPrivate *priv = NULL;
 
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
-       
+       /* Do not need to block, the notify end will do it for us */    
        modest_mail_operation_notify_end (mail_op);
        g_object_unref (mail_op);
 
@@ -856,28 +1151,63 @@ compare_headers_by_date (gconstpointer a,
 static gboolean 
 set_last_updated_idle (gpointer data)
 {
+
+       /* This is a GDK lock because we are an idle callback and
+        * modest_account_mgr_set_int can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED - please recheck */
+
        /* It does not matter if the time is not exactly the same than
           the time when this idle was called, it's just an
           approximation and it won't be very different */
+
        modest_account_mgr_set_int (modest_runtime_get_account_mgr (), 
                                    (gchar *) data, 
                                    MODEST_ACCOUNT_LAST_UPDATED, 
                                    time(NULL), 
                                    TRUE);
 
+       gdk_threads_leave (); /* CHECKED - please recheck */
+
+       return FALSE;
+}
+
+static gboolean
+idle_update_account_cb (gpointer data)
+{
+       UpdateAccountInfo *idle_info;
+
+       idle_info = (UpdateAccountInfo *) data;
+
+       /* This is a GDK lock because we are an idle callback and
+        * idle_info->callback can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED */
+       idle_info->callback (idle_info->mail_op,
+                            idle_info->new_headers,
+                            idle_info->user_data);
+       gdk_threads_leave (); /* CHECKED */
+
+       /* Frees */
+       g_object_unref (idle_info->mail_op);
+       g_free (idle_info);
+
        return FALSE;
 }
 
+
 static gpointer
 update_account_thread (gpointer thr_user_data)
 {
-       UpdateAccountInfo *info;
+       static gboolean first_time = TRUE;
+       UpdateAccountInfo *info = NULL;
        TnyList *all_folders = NULL;
-       GPtrArray *new_headers;
+       GPtrArray *new_headers = NULL;
        TnyIterator *iter = NULL;
        TnyFolderStoreQuery *query = NULL;
-       ModestMailOperationPrivate *priv;
-       ModestTnySendQueue *send_queue;
+       ModestMailOperationPrivate *priv = NULL;
+       ModestTnySendQueue *send_queue = NULL;
+       gint num_new_headers = 0;
 
        info = (UpdateAccountInfo *) thr_user_data;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
@@ -886,11 +1216,17 @@ update_account_thread (gpointer thr_user_data)
        priv->account = g_object_ref (info->account);
 
        /*
-        * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
-        * show any updates unless we do that
+        * Previousl, we did this for POP3, to do a logout-login upon send/receive, 
+        * because many POP-servers (like Gmail) do not
+        * show any updates unless we do that.
+        * But that didn't work with gmail anyway, 
+        * and tinymail now takes care of this itself by disconnecting 
+        * automatically after using the connection.
         */
-       if (TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account)) 
+       /*
+       if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account)) 
                tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
+       */
 
        /* Get all the folders. We can do it synchronously because
           we're already running in a different thread than the UI */
@@ -909,8 +1245,10 @@ update_account_thread (gpointer thr_user_data)
        iter = tny_list_create_iterator (all_folders);
        while (!tny_iterator_is_done (iter)) {
                TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
-
-               recurse_folders (folder, query, all_folders);
+               if (folder) {
+                       recurse_folders (folder, query, all_folders);
+                       g_object_unref (folder);
+               }
                tny_iterator_next (iter);
        }
        g_object_unref (G_OBJECT (iter));
@@ -921,13 +1259,15 @@ update_account_thread (gpointer thr_user_data)
           Gtk+. We use a timeout in order to provide more status
           information, because the sync tinymail call does not
           provide it for the moment */
-       gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
+       gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
 
        /* Refresh folders */
+       num_new_headers = 0;
        new_headers = g_ptr_array_new ();
        iter = tny_list_create_iterator (all_folders);
 
-       while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
+       while (!tny_iterator_is_done (iter) && !priv->error && 
+              priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
 
                InternalFolderObserver *observer;
                TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
@@ -935,8 +1275,6 @@ update_account_thread (gpointer thr_user_data)
                /* Refresh the folder */
                /* Our observer receives notification of new emails during folder refreshes,
                 * so we can use observer->new_headers.
-                * TODO: This does not seem to be providing accurate numbers.
-                * Possibly the observer is notified asynchronously.
                 */
                observer = g_object_new (internal_folder_observer_get_type (), NULL);
                tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
@@ -956,10 +1294,6 @@ update_account_thread (gpointer thr_user_data)
                        iter = tny_list_create_iterator (observer->new_headers);
                        while (!tny_iterator_is_done (iter)) {
                                TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
-                               /* printf ("  DEBUG1.2 %s: checking size: account=%s, subject=%s\n", 
-                                *      __FUNCTION__, tny_account_get_id (priv->account), 
-                                * tny_header_get_subject (header));
-                                */
                                 
                                /* Apply per-message size limits */
                                if (tny_header_get_message_size (header) < info->max_size)
@@ -969,25 +1303,33 @@ update_account_thread (gpointer thr_user_data)
                                tny_iterator_next (iter);
                        }
                        g_object_unref (iter);
+               } else {
+                       /* We do not need to do it the first time
+                          because it's automatically done by the tree
+                          model */
+                       if (G_UNLIKELY (!first_time))
+                               tny_folder_poke_status (TNY_FOLDER (folder));
                }
-               
+
                tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
                g_object_unref (observer);
-               observer = NULL;
+               observer = NULL;                        
+
+               if (folder)
+                       g_object_unref (G_OBJECT (folder));
 
                if (priv->error)
                        priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
 
-               g_object_unref (G_OBJECT (folder));
                tny_iterator_next (iter);
        }
 
-       did_a_cancel = FALSE;
-
        g_object_unref (G_OBJECT (iter));
        g_source_remove (timeout);
 
-       if (new_headers->len > 0) {
+       if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED && 
+           priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
+           new_headers->len > 0) {
                gint msg_num = 0;
 
                /* Order by date */
@@ -998,11 +1340,11 @@ update_account_thread (gpointer thr_user_data)
                 * user to download them all,
                 * as per the UI spec "Retrieval Limits" section in 4.4: 
                 */
-               printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__, 
-                       tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
                if (new_headers->len > info->retrieve_limit) {
-                       /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded, 
-                        * with 'Get all' and 'Newest only' buttons. */
+                       /* TODO: Ask the user, instead of just
+                        * failing, showing
+                        * mail_nc_msg_count_limit_exceeded, with 'Get
+                        * all' and 'Newest only' buttons. */
                        g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
                             "The number of messages to retrieve exceeds the chosen limit for account %s\n", 
@@ -1035,12 +1377,17 @@ update_account_thread (gpointer thr_user_data)
 
                        msg_num++;
                }
-               g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
-               g_ptr_array_free (new_headers, FALSE);
        }
 
-       /* Perform send */
-       priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
+       /* Get the number of new headers and free them */
+       num_new_headers = new_headers->len;
+       g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
+       g_ptr_array_free (new_headers, FALSE);
+       
+       if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
+               goto out;
+
+       /* Perform send (if operation was not cancelled) */
        priv->done = 0;
        priv->total = 0;
        if (priv->account != NULL) 
@@ -1049,9 +1396,7 @@ update_account_thread (gpointer thr_user_data)
        
        send_queue = modest_runtime_get_send_queue (info->transport_account);
        if (send_queue) {
-               timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
                modest_tny_send_queue_try_to_send (send_queue);
-               g_source_remove (timeout);
        } else {
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
@@ -1072,11 +1417,24 @@ update_account_thread (gpointer thr_user_data)
        }
 
  out:
+
+       if (info->callback) {
+               UpdateAccountInfo *idle_info;
+
+               /* This thread is not in the main lock */
+               idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
+               idle_info->mail_op = g_object_ref (info->mail_op);
+               idle_info->new_headers = num_new_headers;
+               idle_info->callback = info->callback;
+               idle_info->user_data = info->user_data;
+               g_idle_add (idle_update_account_cb, idle_info);
+       }
+
        /* Notify about operation end. Note that the info could be
           freed before this idle happens, but the mail operation will
           be still alive */
-       g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
-       
+       g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
+
        /* Frees */
        g_object_unref (query);
        g_object_unref (all_folders);
@@ -1085,30 +1443,27 @@ update_account_thread (gpointer thr_user_data)
        g_free (info->retrieve_type);
        g_slice_free (UpdateAccountInfo, info);
 
+       first_time = FALSE;
+
        return NULL;
 }
 
 gboolean
 modest_mail_operation_update_account (ModestMailOperation *self,
-                                     const gchar *account_name)
+                                     const gchar *account_name,
+                                     UpdateAccountCallback callback,
+                                     gpointer user_data)
 {
-       GThread *thread;
-       UpdateAccountInfo *info;
-       ModestMailOperationPrivate *priv;
-       ModestAccountMgr *mgr;
-       TnyStoreAccount *modest_account;
-       TnyTransportAccount *transport_account;
+       GThread *thread = NULL;
+       UpdateAccountInfo *info = NULL;
+       ModestMailOperationPrivate *priv = NULL;
+       ModestAccountMgr *mgr = NULL;
+       TnyStoreAccount *store_account = NULL;
+       TnyTransportAccount *transport_account = NULL;
 
        g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
        g_return_val_if_fail (account_name, FALSE);
 
-       /* Make sure that we have a connection, and request one 
-        * if necessary:
-        * TODO: Is there some way to trigger this for every attempt to 
-        * use the network? */
-       if (!modest_platform_connect_and_wait(NULL))
-               return FALSE;
-       
        /* Init mail operation. Set total and done to 0, and do not
           update them, this way the progress objects will know that
           we have no clue about the number of the objects */
@@ -1116,21 +1471,25 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        priv->total = 0;
        priv->done  = 0;
        priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
-       
+
        /* Get the Modest account */
-       modest_account = (TnyStoreAccount *)
+       store_account = (TnyStoreAccount *)
                modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
                                                                     account_name,
                                                                     TNY_ACCOUNT_TYPE_STORE);
+                                                                    
+       /* Make sure that we have a connection, and request one 
+        * if necessary:
+        * TODO: Is there some way to trigger this for every attempt to 
+        * use the network? */
+       if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
+               goto error;
 
-       if (!modest_account) {
-               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+       if (!store_account) {
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             "cannot get tny store account for %s\n", account_name);
-               modest_mail_operation_notify_end (self);
-
-               return FALSE;
+               goto error;
        }
 
        
@@ -1140,20 +1499,19 @@ modest_mail_operation_update_account (ModestMailOperation *self,
                modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
                                                                                    account_name);
        if (!transport_account) {
-               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             "cannot get tny transport account for %s\n", account_name);
-               modest_mail_operation_notify_end (self);
-
-               return FALSE;
+               goto error;
        }
 
        /* Create the helper object */
        info = g_slice_new (UpdateAccountInfo);
        info->mail_op = self;
-       info->account = modest_account;
+       info->account = store_account;
        info->transport_account = transport_account;
+       info->callback = callback;
+       info->user_data = user_data;
 
        /* Get the message size limit */
        info->max_size  = modest_conf_get_int (modest_runtime_get_conf (), 
@@ -1183,6 +1541,13 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        thread = g_thread_create (update_account_thread, info, FALSE, NULL);
 
        return TRUE;
+
+ error:
+       priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+       if (callback) 
+               callback (self, 0, user_data);
+       modest_mail_operation_notify_end (self);
+       return FALSE;
 }
 
 /* ******************************************************************* */
@@ -1203,6 +1568,14 @@ modest_mail_operation_create_folder (ModestMailOperation *self,
        
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
+       /* Check for already existing folder */
+       if (modest_tny_folder_has_subfolder_with_name (parent, name)) {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
+                            _CS("ckdg_ib_folder_already_exists"));
+       }
+
        /* Check parent */
        if (TNY_IS_FOLDER (parent)) {
                /* Check folder rules */
@@ -1216,6 +1589,13 @@ modest_mail_operation_create_folder (ModestMailOperation *self,
                }
        }
 
+       if (!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,
+                            _("mail_in_ui_folder_create_error"));
+       }
+
        if (!priv->error) {
                /* Create the folder */
                new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
@@ -1265,14 +1645,21 @@ modest_mail_operation_remove_folder (ModestMailOperation *self,
                trash_folder = modest_tny_account_get_special_folder (account,
                                                                      TNY_FOLDER_TYPE_TRASH);
                /* TODO: error_handling */
-                modest_mail_operation_xfer_folder (self, folder,
-                                                   TNY_FOLDER_STORE (trash_folder), TRUE);
+               if (trash_folder) {
+                       modest_mail_operation_xfer_folder (self, folder,
+                                                   TNY_FOLDER_STORE (trash_folder), 
+                                                   TRUE, NULL, NULL);
+                       g_object_unref (trash_folder);
+               }
        } else {
                TnyFolderStore *parent = tny_folder_get_folder_store (folder);
 
                tny_folder_store_remove_folder (parent, folder, &(priv->error));
                CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
 
+               if (!priv->error)
+                       priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+
                if (parent)
                        g_object_unref (G_OBJECT (parent));
        }
@@ -1291,41 +1678,55 @@ transfer_folder_status_cb (GObject *obj,
        ModestMailOperation *self;
        ModestMailOperationPrivate *priv;
        ModestMailOperationState *state;
+       XFerMsgAsyncHelper *helper;
 
        g_return_if_fail (status != NULL);
        g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
 
-       self = MODEST_MAIL_OPERATION (user_data);
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
+       helper = (XFerMsgAsyncHelper *) user_data;
+       g_return_if_fail (helper != NULL);
 
-       if ((status->position == 1) && (status->of_total == 100))
-               return;
+       self = helper->mail_op;
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
        priv->done = status->position;
        priv->total = status->of_total;
 
        state = modest_mail_operation_clone_state (self);
-       g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
+
+       /* This is not a GDK lock because we are a Tinymail callback
+        * which is already GDK locked by Tinymail */
+
+       /* no gdk_threads_enter (), CHECKED */
+
+       g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL); 
+
+       /* no gdk_threads_leave (), CHECKED */
+
        g_slice_free (ModestMailOperationState, state);
 }
 
 
 static void
 transfer_folder_cb (TnyFolder *folder, 
-                   TnyFolderStore *into, 
                    gboolean cancelled, 
-                   TnyFolder *new_folder, GError **err, 
+                   TnyFolderStore *into, 
+                   TnyFolder *new_folder, 
+                   GError *err, 
                    gpointer user_data)
 {
+       XFerMsgAsyncHelper *helper;
        ModestMailOperation *self = NULL;
        ModestMailOperationPrivate *priv = NULL;
 
-       self = MODEST_MAIL_OPERATION (user_data);
+       helper = (XFerMsgAsyncHelper *) user_data;
+       g_return_if_fail (helper != NULL);       
 
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+       self = helper->mail_op;
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       if (*err) {
-               priv->error = g_error_copy (*err);
+       if (err) {
+               priv->error = g_error_copy (err);
                priv->done = 0;
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
        } else if (cancelled) {
@@ -1339,30 +1740,116 @@ transfer_folder_cb (TnyFolder *folder,
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
                
-       /* Free */
-       g_object_unref (folder);
-       g_object_unref (into);
-       if (new_folder != NULL)
-               g_object_unref (new_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
+                * which is already GDK locked by Tinymail */
+
+               /* no gdk_threads_enter (), CHECKED */
+               helper->user_callback (priv->source, helper->user_data);
+               /* no gdk_threads_leave () , CHECKED */
+       }
+
+       /* Free */
+       g_object_unref (helper->mail_op);
+       g_slice_free   (XFerMsgAsyncHelper, helper);
+}
+
+/**
+ *
+ * This function checks if the new name is a valid name for our local
+ * folders account. The new name could not be the same than then name
+ * of any of the mandatory local folders
+ *
+ * We can not rely on tinymail because tinymail does not check the
+ * name of the virtual folders that the account could have in the case
+ * that we're doing a rename (because it directly calls Camel which
+ * knows nothing about our virtual folders). 
+ *
+ * In the case of an actual copy/move (i.e. move/copy a folder between
+ * accounts) tinymail uses the tny_folder_store_create_account which
+ * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
+ * checks the new name of the folder, so this call in that case
+ * wouldn't be needed. *But* NOTE that if tinymail changes its
+ * implementation (if folder transfers within the same account is no
+ * longer implemented as a rename) this call will allow Modest to work
+ * perfectly
+ *
+ * If the new name is not valid, this function will set the status to
+ * failed and will set also an error in the mail operation
+ */
+static gboolean
+new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
+                                TnyFolderStore *into,
+                                const gchar *new_name)
+{
+       if (TNY_IS_ACCOUNT (into) && 
+           modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
+           modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
+                                                                new_name)) {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
+                            _("ckdg_ib_folder_already_exists"));
+               return FALSE;
+       } else
+               return TRUE;
+}
+
+/**
+ * This function checks if @ancestor is an acestor of @folder and
+ * returns TRUE in that case
+ */
+static gboolean
+folder_is_ancestor (TnyFolder *folder,
+                   TnyFolderStore *ancestor)
+{
+       TnyFolder *tmp = NULL;
+       gboolean found = FALSE;
+
+       tmp = folder;
+       while (!found && tmp && !TNY_IS_ACCOUNT (tmp)) {
+               TnyFolderStore *folder_store;
+
+               folder_store = tny_folder_get_folder_store (tmp);
+               if (ancestor == folder_store)
+                       found = TRUE;
+               else
+                       tmp = g_object_ref (folder_store);
+               g_object_unref (folder_store);
+       }
+       return found;
 }
 
 void
 modest_mail_operation_xfer_folder (ModestMailOperation *self,
                                   TnyFolder *folder,
                                   TnyFolderStore *parent,
-                                  gboolean delete_original)
+                                  gboolean delete_original,
+                                  XferMsgsAsynUserCallback user_callback,
+                                  gpointer user_data)
 {
        ModestMailOperationPrivate *priv = NULL;
-       ModestTnyFolderRules parent_rules, rules;
+       ModestTnyFolderRules parent_rules = 0, rules; 
+       XFerMsgAsyncHelper *helper = NULL;
+       const gchar *folder_name = NULL;
+       const gchar *error_msg;
 
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_FOLDER (folder));
-       g_return_if_fail (TNY_IS_FOLDER (parent));
+       g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+       folder_name = tny_folder_get_name (folder);
+
+       /* Set the error msg */
+       error_msg = (delete_original) ? 
+               _("mail_in_ui_folder_move_target_error") : 
+               _("mail_in_ui_folder_copy_target_error");
 
        /* Get account and set it into mail_operation */
        priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
@@ -1370,36 +1857,82 @@ modest_mail_operation_xfer_folder (ModestMailOperation *self,
 
        /* Get folder rules */
        rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
-       parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
-
-       if (!TNY_IS_FOLDER_STORE (parent)) {
-               
-       }
+       if (TNY_IS_FOLDER (parent))
+               parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
        
        /* The moveable restriction is applied also to copy operation */
-       if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
+       if ((gpointer) parent == (gpointer) folder ||
+           (!TNY_IS_FOLDER_STORE (parent)) || 
+           (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
+
                /* Set status failed and set an error */
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
-                            _("mail_in_ui_folder_move_target_error"));
+                            error_msg);
 
                /* Notify the queue */
                modest_mail_operation_notify_end (self);
-       } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
+
+       } else if (TNY_IS_FOLDER (parent) && 
+                  (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
+
                /* Set status failed and set an error */
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
-                            _("FIXME: parent folder does not accept new folders"));
+                            error_msg);
 
                /* Notify the queue */
                modest_mail_operation_notify_end (self);
-       } else {
-               /* Pick references for async calls */
-               g_object_ref (folder);
-               g_object_ref (parent);
 
+       } else if (TNY_IS_FOLDER (parent) &&
+                  TNY_IS_FOLDER_STORE (folder) &&
+                  folder_is_ancestor (TNY_FOLDER (parent), TNY_FOLDER_STORE (folder))) {
+               /* Set status failed and set an error */
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
+                            error_msg);
+
+               /* Notify the queue */
+               modest_mail_operation_notify_end (self);
+
+       } else if (TNY_IS_FOLDER_STORE (parent) &&
+                  modest_tny_folder_has_subfolder_with_name (parent, folder_name)) {
+               /* Check that the new folder name is not used by any
+                   parent subfolder */
+
+               /* Set status failed and set an error */
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
+                            error_msg);
+
+               /* Notify the queue */
+               modest_mail_operation_notify_end (self);
+               
+       } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
+               /* Check that the new folder name is not used by any
+                  special local folder */
+
+               /* Set status failed and set an error */
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
+                            error_msg);
+
+               /* Notify the queue */
+               modest_mail_operation_notify_end (self);
+       } else {
+               /* Create the helper */
+               helper = g_slice_new0 (XFerMsgAsyncHelper);
+               helper->mail_op = g_object_ref(self);
+               helper->dest_folder = NULL;
+               helper->headers = NULL;
+               helper->user_callback = user_callback;
+               helper->user_data = user_data;
+               
                /* Move/Copy folder */          
                tny_folder_copy_async (folder,
                                       parent,
@@ -1407,8 +1940,9 @@ modest_mail_operation_xfer_folder (ModestMailOperation *self,
                                       delete_original,
                                       transfer_folder_cb,
                                       transfer_folder_status_cb,
-                                      self);
-       }
+                                      helper);         
+       } 
+       
 }
 
 void
@@ -1418,6 +1952,7 @@ modest_mail_operation_rename_folder (ModestMailOperation *self,
 {
        ModestMailOperationPrivate *priv;
        ModestTnyFolderRules rules;
+       XFerMsgAsyncHelper *helper;
 
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
@@ -1439,20 +1974,40 @@ modest_mail_operation_rename_folder (ModestMailOperation *self,
 
                /* Notify about operation end */
                modest_mail_operation_notify_end (self);
+       } else if (!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,
+                            _("FIXME: unable to rename"));
+               /* Notify about operation end */
+               modest_mail_operation_notify_end (self);
        } else {
-               /* Rename. Camel handles folder subscription/unsubscription */
                TnyFolderStore *into;
 
-               into = tny_folder_get_folder_store (folder);
-               tny_folder_copy_async (folder, into, name, TRUE,
-                                transfer_folder_cb,
-                                transfer_folder_status_cb,
-                                self);
-               if (into)
-                       g_object_unref (into);
+               into = tny_folder_get_folder_store (folder);    
+
+               /* Check that the new folder name is not used by any
+                  special local folder */
+               if (new_name_valid_if_local_account (priv, into, name)) {
+                       /* Create the helper */
+                       helper = g_slice_new0 (XFerMsgAsyncHelper);
+                       helper->mail_op = g_object_ref(self);
+                       helper->dest_folder = NULL;
+                       helper->headers = NULL;
+                       helper->user_callback = NULL;
+                       helper->user_data = NULL;
                
+                       /* Rename. Camel handles folder subscription/unsubscription */
+                       tny_folder_copy_async (folder, into, name, TRUE,
+                                              transfer_folder_cb,
+                                              transfer_folder_status_cb,
+                                              helper);
+               } else {
+                       modest_mail_operation_notify_end (self);
+               }
+               g_object_unref (into);
        }
- }
+}
 
 /* ******************************************************************* */
 /* **************************  MSG  ACTIONS  ************************* */
@@ -1479,11 +2034,23 @@ void modest_mail_operation_get_msg (ModestMailOperation *self,
        if (folder) {
                /* Get account and set it into mail_operation */
                priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
+               
+               /* Check for cached messages */
+               if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
+                       priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
+               else 
+                       priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
 
                helper = g_slice_new0 (GetMsgAsyncHelper);
                helper->mail_op = self;
                helper->user_callback = user_callback;
                helper->user_data = user_data;
+               helper->header = g_object_ref (header);
+
+               // The callback's reference so that the mail op is not
+               // finalized until the async operation is completed even if
+               // the user canceled the request meanwhile.
+               g_object_ref (G_OBJECT (helper->mail_op));
 
                tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
 
@@ -1504,7 +2071,7 @@ static void
 get_msg_cb (TnyFolder *folder, 
            gboolean cancelled, 
            TnyMsg *msg, 
-           GError **error, 
+           GError *error, 
            gpointer user_data)
 {
        GetMsgAsyncHelper *helper = NULL;
@@ -1518,33 +2085,37 @@ get_msg_cb (TnyFolder *folder,
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
        /* Check errors and cancel */
-       if (*error) {
-               priv->error = g_error_copy (*error);
+       if (error) {
+               priv->error = g_error_copy (error);
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
-               goto out;
-       }
-       if (cancelled) {
+       } else if (cancelled) {
                priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             _("Error trying to refresh the contents of %s"),
                             tny_folder_get_name (folder));
-               goto out;
+       } else {
+               priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
 
-       priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
-
-       /* If user defined callback function was defined, call it */
+       /* If user defined callback function was defined, call it even
+          if the operation failed*/
        if (helper->user_callback) {
-               helper->user_callback (self, NULL, msg, helper->user_data);
+               /* This is not a GDK lock because we are a Tinymail callback
+                * which is already GDK locked by Tinymail */
+
+               /* no gdk_threads_enter (), CHECKED */
+               helper->user_callback (self, helper->header, msg, helper->user_data);
+               /* no gdk_threads_leave (), CHECKED */
        }
 
- out:
+       /* Notify about operation end */
+       modest_mail_operation_notify_end (self);
        /* Free */
+       g_object_unref (helper->mail_op);
+       g_object_unref (helper->header);
        g_slice_free (GetMsgAsyncHelper, helper);
                
-       /* Notify about operation end */
-       modest_mail_operation_notify_end (self);        
 }
 
 static void     
@@ -1566,14 +2137,20 @@ get_msg_status_cb (GObject *obj,
        self = helper->mail_op;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       if ((status->position == 1) && (status->of_total == 100))
-               return;
-
        priv->done = 1;
        priv->total = 1;
 
        state = modest_mail_operation_clone_state (self);
+       state->bytes_done = status->position;
+       state->bytes_total = status->of_total;
+
+       /* This is not a GDK lock because we are a Tinymail callback
+        * which is already GDK locked by Tinymail */
+
+       /* no gdk_threads_enter (), CHECKED */
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
+       /* no gdk_threads_leave (), CHECKED */
+
        g_slice_free (ModestMailOperationState, state);
 }
 
@@ -1606,8 +2183,12 @@ notify_get_msgs_full (gpointer data)
 
        info = (NotifyGetMsgsInfo *) data;      
 
-       /* Call the user callback */
+       /* This is a GDK lock because we are an idle callback and
+        * because info->user_callback can contain Gtk+ code */
+
+       gdk_threads_enter (); /* CHECKED */
        info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
+       gdk_threads_leave (); /* CHECKED */
 
        g_slice_free (NotifyGetMsgsInfo, info);
 
@@ -1625,8 +2206,15 @@ get_msgs_full_destroyer (gpointer data)
 
        info = (GetFullMsgsInfo *) data;
 
-       if (info->notify)
+       if (info->notify) {
+
+               /* This is a GDK lock because we are an idle callback and
+                * because info->notify can contain Gtk+ code */
+
+               gdk_threads_enter (); /* CHECKED */
                info->notify (info->user_data);
+               gdk_threads_leave (); /* CHECKED */
+       }
 
        /* free */
        g_object_unref (info->headers);
@@ -1653,6 +2241,12 @@ get_msgs_full_thread (gpointer thr_user_data)
                header = TNY_HEADER (tny_iterator_get_current (iter));
                folder = tny_header_get_folder (header);
                                
+               /* Check for cached messages */
+               if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
+                       priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
+               else 
+                       priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
+
                /* Get message from folder */
                if (folder) {
                        TnyMsg *msg;
@@ -1686,7 +2280,7 @@ get_msgs_full_thread (gpointer thr_user_data)
                                                         info_notify, NULL);
                                }
                                g_object_unref (msg);
-                       }
+                       } 
                } else {
                        /* Set status failed and set an error */
                        priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
@@ -1694,7 +2288,10 @@ get_msgs_full_thread (gpointer thr_user_data)
                                     MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                                     "Error trying to get a message. No folder found for header");
                }
-               g_object_unref (header);                
+
+               if (header)
+                       g_object_unref (header);
+               
                tny_iterator_next (iter);
        }
 
@@ -1703,7 +2300,7 @@ get_msgs_full_thread (gpointer thr_user_data)
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
 
        /* Notify about operation end */
-       g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
+       g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
 
        /* Free thread resources. Will be called after all previous idles */
        g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
@@ -1739,10 +2336,16 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self,
        if (tny_list_get_length (header_list) >= 1) {
                iter = tny_list_create_iterator (header_list);
                header = TNY_HEADER (tny_iterator_get_current (iter));
-               folder = tny_header_get_folder (header);                
-               priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
-               g_object_unref (header);
-               g_object_unref (folder);
+               if (header) {
+                       folder = tny_header_get_folder (header);
+                       if (folder) {           
+                               priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
+
+                               g_object_unref (folder);
+                       }
+
+                       g_object_unref (header);
+               }
 
                if (tny_list_get_length (header_list) == 1) {
                        g_object_unref (iter);
@@ -1766,9 +2369,12 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self,
        if (iter != NULL) {
                while (!tny_iterator_is_done (iter) && size_ok) {
                        header = TNY_HEADER (tny_iterator_get_current (iter));
-                       if (tny_header_get_message_size (header) >= max_size)
-                               size_ok = FALSE;
-                       g_object_unref (header);
+                       if (header) {
+                               if (tny_header_get_message_size (header) >= max_size)
+                                       size_ok = FALSE;
+                               g_object_unref (header);
+                       }
+
                        tny_iterator_next (iter);
                }
                g_object_unref (iter);
@@ -1800,9 +2406,9 @@ modest_mail_operation_get_msgs_full (ModestMailOperation *self,
 
 
 void 
-modest_mail_operation_remove_msg (ModestMailOperation *self,
+modest_mail_operation_remove_msg (ModestMailOperation *self,  
                                  TnyHeader *header,
-                                 gboolean remove_to_trash)
+                                 gboolean remove_to_trash /*ignored*/)
 {
        TnyFolder *folder;
        ModestMailOperationPrivate *priv;
@@ -1810,6 +2416,9 @@ modest_mail_operation_remove_msg (ModestMailOperation *self,
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_HEADER (header));
 
+       if (remove_to_trash)
+               g_warning ("remove to trash is not implemented");
+
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
        folder = tny_header_get_folder (header);
 
@@ -1818,44 +2427,82 @@ modest_mail_operation_remove_msg (ModestMailOperation *self,
 
        priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
 
-       /* Delete or move to trash */
-       if (remove_to_trash) {
-               TnyFolder *trash_folder;
-               TnyStoreAccount *store_account;
+       /* remove message from folder */
+       tny_folder_remove_msg (folder, header, &(priv->error));
+       if (!priv->error) {
+               tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
+               tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
+
+               if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
+/*                     tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
+                       tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
+               else if (TNY_IS_CAMEL_POP_FOLDER (folder))
+/*                     tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
+                       tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
+               else
+                       /* local folders */
+/*                     tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
+                       tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
+       }
+       
+       
+       /* Set status */
+       if (!priv->error)
+               priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+       else
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
 
-               store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
-               trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
-                                                                     TNY_FOLDER_TYPE_TRASH);
-               if (trash_folder) {
-                       TnyList *headers;
+       /* Free */
+       g_object_unref (G_OBJECT (folder));
 
-                       /* Create list */
-                       headers = tny_simple_list_new ();
-                       tny_list_append (headers, G_OBJECT (header));
-                       g_object_unref (header);
+       /* Notify about operation end */
+       modest_mail_operation_notify_end (self);
+}
 
-                       /* Move to trash */
-                       modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
-                       g_object_unref (headers);
-/*                     g_object_unref (trash_folder); */
-               } else {
-                       ModestMailOperationPrivate *priv;
+void 
+modest_mail_operation_remove_msgs (ModestMailOperation *self,  
+                                  TnyList *headers,
+                                 gboolean remove_to_trash /*ignored*/)
+{
+       TnyFolder *folder;
+       ModestMailOperationPrivate *priv;
+       TnyIterator *iter = NULL;
+       TnyHeader *header = NULL;
 
-                       /* Set status failed and set an error */
-                       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
-                       priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
-                       g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
-                                    MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
-                                    _("Error trying to delete a message. Trash folder not found"));
-               }
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       g_return_if_fail (TNY_IS_LIST (headers));
 
-               g_object_unref (G_OBJECT (store_account));
-       } else {
-               tny_folder_remove_msg (folder, header, &(priv->error));
-               if (!priv->error)
-                       tny_folder_sync(folder, TRUE, &(priv->error));
-       }
+       if (remove_to_trash)
+               g_warning ("remove to trash is not implemented");
+
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+
+       /* Get folder from first header and sync it */
+       iter = tny_list_create_iterator (headers);
+       header = TNY_HEADER (tny_iterator_get_current (iter));
+       folder = tny_header_get_folder (header);
+       
+       /* Get account and set it into mail_operation */
+       priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
 
+       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
+
+       /* remove message from folder */
+       tny_folder_remove_msgs (folder, headers, &(priv->error));
+       if (!priv->error) {
+               if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
+/*                     tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* FALSE --> don't expunge *\/ */
+                       tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
+               else if (TNY_IS_CAMEL_POP_FOLDER (folder))
+/*                     tny_folder_sync_async(folder, FALSE, NULL, NULL, NULL); /\* TRUE --> dont expunge *\/ */
+                       tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
+               else
+                       /* local folders */
+/*                     tny_folder_sync_async(folder, TRUE, NULL, NULL, NULL); /\* TRUE --> expunge *\/ */
+                       tny_folder_sync (folder, TRUE, &(priv->error)); /* TRUE --> expunge */
+       }
+       
+       
        /* Set status */
        if (!priv->error)
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
@@ -1863,12 +2510,15 @@ modest_mail_operation_remove_msg (ModestMailOperation *self,
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
 
        /* Free */
+       g_object_unref (header);
+       g_object_unref (iter);
        g_object_unref (G_OBJECT (folder));
 
        /* Notify about operation end */
        modest_mail_operation_notify_end (self);
 }
 
+
 static void
 transfer_msgs_status_cb (GObject *obj,
                         TnyStatus *status,  
@@ -1889,32 +2539,40 @@ transfer_msgs_status_cb (GObject *obj,
        self = helper->mail_op;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       if ((status->position == 1) && (status->of_total == 100))
-               return;
-
        priv->done = status->position;
        priv->total = status->of_total;
 
        state = modest_mail_operation_clone_state (self);
+
+       /* This is not a GDK lock because we are a Tinymail callback and
+        * Tinymail already acquires the Gdk lock */
+
+       /* no gdk_threads_enter (), CHECKED */
+
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
+
+       /* no gdk_threads_leave (), CHECKED */
+
        g_slice_free (ModestMailOperationState, state);
 }
 
 
 static void
-transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
+transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
 {
        XFerMsgAsyncHelper *helper;
        ModestMailOperation *self;
        ModestMailOperationPrivate *priv;
+       TnyIterator *iter = NULL;
+       TnyHeader *header = NULL;
 
        helper = (XFerMsgAsyncHelper *) user_data;
        self = helper->mail_op;
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
-       if (*err) {
-               priv->error = g_error_copy (*err);
+       if (err) {
+               priv->error = g_error_copy (err);
                priv->done = 0;
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
        } else if (cancelled) {
@@ -1926,22 +2584,55 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer
        } else {
                priv->done = 1;
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
+
+               /* Update folder counts */
+               tny_folder_poke_status (folder);                
+               tny_folder_poke_status (helper->dest_folder);           
        }
 
+       
+       /* 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_flags (header, TNY_HEADER_FLAG_DELETED);
+                       tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
+                       g_object_unref (header);
+
+                       tny_iterator_next (iter);
+               }
+
+       }
+               
+
+       /* 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 (priv->source, helper->user_data);
+               /* no gdk_threads_leave (), CHECKED */
        }
 
        /* Free */
-       g_object_unref (helper->headers);
-       g_object_unref (helper->dest_folder);
-       g_object_unref (helper->mail_op);
+       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   (XFerMsgAsyncHelper, helper);
-       g_object_unref (folder);
 
-       /* Notify about operation end */
-       modest_mail_operation_notify_end (self);
 }
 
 void
@@ -1952,12 +2643,15 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
                                 XferMsgsAsynUserCallback user_callback,
                                 gpointer user_data)
 {
-       ModestMailOperationPrivate *priv;
-       TnyIterator *iter;
-       TnyFolder *src_folder;
-       XFerMsgAsyncHelper *helper;
-       TnyHeader *header;
-       ModestTnyFolderRules rules;
+       ModestMailOperationPrivate *priv = NULL;
+       TnyIterator *iter = NULL;
+       TnyFolder *src_folder = NULL;
+       XFerMsgAsyncHelper *helper = NULL;
+       TnyHeader *header = NULL;
+       ModestTnyFolderRules rules = 0;
+       const gchar *id1 = NULL;
+       const gchar *id2 = NULL;
+       gboolean same_folder = FALSE;
 
        g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
        g_return_if_fail (TNY_IS_LIST (headers));
@@ -1970,17 +2664,45 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
 
        /* Apply folder rules */
        rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
-
        if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
                /* Set status failed and set an error */
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
                g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
                             MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
-                            _("FIXME: folder does not accept msgs"));
+                            _CS("ckct_ib_unable_to_paste_here"));
                /* Notify the queue */
                modest_mail_operation_notify_end (self);
                return;
        }
+               
+       /* Get source folder */
+       iter = tny_list_create_iterator (headers);
+       header = TNY_HEADER (tny_iterator_get_current (iter));
+       if (header) {
+               src_folder = tny_header_get_folder (header);
+               g_object_unref (header);
+       }
+
+       g_object_unref (iter);
+
+       /* Check folder source and destination */
+       id1 = tny_folder_get_id (src_folder);
+       id2 = tny_folder_get_id (TNY_FOLDER(folder));
+       same_folder = !g_ascii_strcasecmp (id1, id2);
+       if (same_folder) {
+               /* Set status failed and set an error */
+               priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
+                            _("mcen_ib_unable_to_copy_samefolder"));
+               
+               /* Notify the queue */
+               modest_mail_operation_notify_end (self);
+               
+               /* Free */
+               g_object_unref (src_folder);            
+               return;
+       }
 
        /* Create the helper */
        helper = g_slice_new0 (XFerMsgAsyncHelper);
@@ -1989,13 +2711,7 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
        helper->headers = g_object_ref(headers);
        helper->user_callback = user_callback;
        helper->user_data = user_data;
-
-       /* Get source folder */
-       iter = tny_list_create_iterator (headers);
-       header = TNY_HEADER (tny_iterator_get_current (iter));
-       src_folder = tny_header_get_folder (header);
-       g_object_unref (header);
-       g_object_unref (iter);
+       helper->delete = delete_original;
 
        /* Get account and set it into mail_operation */
        priv->account = modest_tny_folder_get_account (src_folder);
@@ -2014,7 +2730,7 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
 static void
 on_refresh_folder (TnyFolder   *folder, 
                   gboolean     cancelled, 
-                  GError     **error,
+                  GError     *error,
                   gpointer     user_data)
 {
        RefreshAsyncHelper *helper = NULL;
@@ -2025,9 +2741,13 @@ on_refresh_folder (TnyFolder   *folder,
        self = helper->mail_op;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       if (*error) {
-               priv->error = g_error_copy (*error);
+       g_return_if_fail(priv!=NULL);
+
+       if (error) {
+               priv->error = g_error_copy (error);
                priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
+               printf("DEBUG: %s: Operation error:\n %s", __FUNCTION__,
+                      error->message);
                goto out;
        }
 
@@ -2037,23 +2757,27 @@ on_refresh_folder (TnyFolder   *folder,
                             MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
                             _("Error trying to refresh the contents of %s"),
                             tny_folder_get_name (folder));
+               printf("DEBUG: %s: Operation cancelled.\n", __FUNCTION__);
                goto out;
        }
 
        priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
 
- out:
        /* Call user defined callback, if it exists */
-       if (helper->user_callback)
-               helper->user_callback (priv->source, folder, helper->user_data);
+       if (helper->user_callback) {
+
+               /* This is not a GDK lock because we are a Tinymail callback and
+                * Tinymail already acquires the Gdk lock */
+               helper->user_callback (self, folder, helper->user_data);
+       }
 
+ out:
        /* Free */
-       g_object_unref (helper->mail_op);
        g_slice_free   (RefreshAsyncHelper, helper);
-       g_object_unref (folder);
 
        /* Notify about operation end */
        modest_mail_operation_notify_end (self);
+       g_object_unref(self);
 }
 
 static void
@@ -2080,7 +2804,11 @@ on_refresh_folder_status_update (GObject *obj,
        priv->total = status->of_total;
 
        state = modest_mail_operation_clone_state (self);
+
+       /* This is not a GDK lock because we are a Tinymail callback and
+        * Tinymail already acquires the Gdk lock */
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
+
        g_slice_free (ModestMailOperationState, state);
 }
 
@@ -2095,9 +2823,6 @@ modest_mail_operation_refresh_folder  (ModestMailOperation *self,
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       /* Pick a reference */
-       g_object_ref (folder);
-
        priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
 
        /* Get account and set it into mail_operation */
@@ -2136,20 +2861,17 @@ modest_mail_operation_notify_end (ModestMailOperation *self)
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
 
-       if (!priv) {
-               g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
-               return;
-       }
-       
        /* Set the account back to not busy */
        if (priv->account_name) {
-               modest_account_mgr_set_account_busy(modest_runtime_get_account_mgr(), priv->account_name,
-                                                                                                                                                               FALSE);
+               modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(), 
+                                                    priv->account_name, FALSE);
                g_free(priv->account_name);
                priv->account_name = NULL;
        }
        
-       /* Notify the observers about the mail opertation end */
+       /* Notify the observers about the mail operation end */
+       /* We do not wrapp this emission because we assume that this
+          function is always called from within the main lock */
        state = modest_mail_operation_clone_state (self);
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
        g_slice_free (ModestMailOperationState, state);