* also allow pop-accounts to come without authentication options;
[modest] / src / modest-mail-operation.c
index bad26b1..4ca932b 100644 (file)
@@ -41,6 +41,7 @@
 #include <tny-status.h>
 #include <camel/camel-stream-mem.h>
 #include <glib/gi18n.h>
+#include "modest-platform.h"
 #include <modest-tny-account.h>
 #include <modest-tny-send-queue.h>
 #include <modest-runtime.h>
@@ -56,9 +57,9 @@ static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
 static void modest_mail_operation_init       (ModestMailOperation *obj);
 static void modest_mail_operation_finalize   (GObject *obj);
 
-static void     update_process_msg_status_cb (GObject *obj,
-                                             TnyStatus *status,  
-                                             gpointer user_data);
+/* static void     update_process_msg_status_cb (GObject *obj, */
+/*                                           TnyStatus *status,   */
+/*                                           gpointer user_data); */
 static void     get_msg_cb (TnyFolder *folder, 
                            gboolean cancelled, 
                            TnyMsg *msg, 
@@ -84,6 +85,7 @@ struct _ModestMailOperationPrivate {
        ModestMailOperationStatus  status;      
        ModestMailOperationId      id;          
        GObject                   *source;
+       ErrorCheckingUserCallback  error_checking;
        GError                    *error;
 };
 
@@ -102,21 +104,13 @@ typedef struct _GetMsgAsyncHelper {
        gpointer user_data;
 } GetMsgAsyncHelper;
 
-typedef struct _RefreshFolderAsyncHelper
-{
-       ModestMailOperation *mail_op;
-       TnyIterator *iter;
-       guint failed;
-       guint canceled;
-
-} RefreshFolderAsyncHelper;
-
 typedef struct _XFerMsgAsyncHelper
 {
        ModestMailOperation *mail_op;
        TnyList *headers;
        TnyFolder *dest_folder;
-
+       XferMsgsAsynUserCallback user_callback; 
+       gpointer user_data;
 } XFerMsgAsyncHelper;
 
 typedef struct _XFerFolderAsyncHelper
@@ -125,7 +119,6 @@ typedef struct _XFerFolderAsyncHelper
 
 } XFerFolderAsyncHelper;
 
-
 /* globals */
 static GObjectClass *parent_class = NULL;
 
@@ -234,6 +227,35 @@ modest_mail_operation_new (ModestMailOperationId id,
        return obj;
 }
 
+ModestMailOperation*
+modest_mail_operation_new_with_error_handling (ModestMailOperationId id,
+                                              GObject *source,
+                                              ErrorCheckingUserCallback error_handler)
+{
+       ModestMailOperation *obj;
+       ModestMailOperationPrivate *priv;
+               
+       obj = modest_mail_operation_new (id, source);
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
+       
+       g_return_val_if_fail (error_handler != NULL, obj);
+       priv->error_checking = error_handler;
+
+       return obj;
+}
+
+void
+modest_mail_operation_execute_error_handler (ModestMailOperation *self)
+{
+       ModestMailOperationPrivate *priv;
+       
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
+       g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);     
+
+       if (priv->error_checking == NULL) return;       
+       priv->error_checking (priv->source, self);
+}
+
 
 ModestMailOperationId
 modest_mail_operation_get_id (ModestMailOperation *self)
@@ -395,7 +417,7 @@ typedef struct
 {
        ModestMailOperation *mail_op;
        TnyStoreAccount *account;
-       gpointer user_data;
+       TnyTransportAccount *transport_account;
 } UpdateAccountInfo;
 
 static void
@@ -422,8 +444,8 @@ recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all
 }
 
 /* 
- * Used by update_account_thread to emit the signal from the main
- * loop. We call it inside an idle call to achieve that 
+ * Used by update_account_thread to emit the "progress-changed" signal
+ * from the main loop. We call it inside an idle call to achieve that
  */
 static gboolean
 notify_update_account_observers (gpointer data)
@@ -431,9 +453,8 @@ notify_update_account_observers (gpointer data)
        ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
 
        g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
-       g_object_unref (mail_op);
 
-       return FALSE;
+       return TRUE;
 }
 
 /* 
@@ -460,6 +481,8 @@ update_account_thread (gpointer thr_user_data)
        TnyIterator *iter = NULL;
        TnyFolderStoreQuery *query = NULL;
        ModestMailOperationPrivate *priv;
+       ModestTnySendQueue *send_queue;
+       gint timeout;
 
        info = (UpdateAccountInfo *) thr_user_data;
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
@@ -487,6 +510,14 @@ update_account_thread (gpointer thr_user_data)
        }
        g_object_unref (G_OBJECT (iter));
 
+       /* Update status and notify. We need to call the notification
+          with a source functopm in order to call it from the main
+          loop. We need that in order not to get into trouble with
+          Gtk+. We use a timeout in order to provide more status
+          information, because the sync tinymail call does not
+          provide it for the moment */
+       timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
+
        /* Refresh folders */
        iter = tny_list_create_iterator (all_folders);
        while (!tny_iterator_is_done (iter) && !priv->error) {
@@ -496,21 +527,33 @@ update_account_thread (gpointer thr_user_data)
                /* Refresh the folder */
                tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
 
+               /* TODO: Apply retrieval types */
+
+               /* TODO: apply per-message size limits */
+
+               /* TODO: apply message count limit */
+
                if (priv->error) {
                        priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
-               } else {
-                       /* Update status and notify. We need to call
-                          the notification with an idle in order to
-                          call it from the main loop. We need that in
-                          order not to get into trouble with Gtk+ */
-                       g_idle_add (notify_update_account_observers, g_object_ref (info->mail_op));
                }
 
                g_object_unref (G_OBJECT (folder));
                tny_iterator_next (iter);
        }
        g_object_unref (G_OBJECT (iter));
+       g_source_remove (timeout);
+
+       /* Perform send */
+       priv->id = MODEST_MAIL_OPERATION_ID_SEND;
+
+       send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
+
+       timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
+       modest_tny_send_queue_flush (send_queue);
+       g_source_remove (timeout);
 
+       g_object_unref (G_OBJECT(send_queue));
+       
        /* Check if the operation was a success */
        if (!priv->error) {
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
@@ -524,14 +567,16 @@ update_account_thread (gpointer thr_user_data)
        }
 
  out:
-       /* Notify the queue */
-       g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
+       /* Notify the queue. 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, info->mail_op);
 
        /* Frees */
        g_object_unref (query);
        g_object_unref (all_folders);
-       g_object_unref (info->mail_op);
        g_object_unref (info->account);
+       g_object_unref (info->transport_account);
        g_slice_free (UpdateAccountInfo, info);
 
        return NULL;
@@ -545,6 +590,7 @@ modest_mail_operation_update_account (ModestMailOperation *self,
        UpdateAccountInfo *info;
        ModestMailOperationPrivate *priv;
        TnyStoreAccount *modest_account;
+       TnyTransportAccount *transport_account;
 
        g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
        g_return_val_if_fail (account_name, FALSE);
@@ -565,6 +611,24 @@ modest_mail_operation_update_account (ModestMailOperation *self,
 
        if (!modest_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 store account for %s\n", account_name);
+               modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
+                                                   self);
+               return FALSE;
+       }
+
+       /* Get the transport account, we can not do it in the thread
+          due to some problems with dbus */
+       transport_account = (TnyTransportAccount *)
+               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_queue_remove (modest_runtime_get_mail_operation_queue (), 
                                                    self);
                return FALSE;
@@ -572,9 +636,9 @@ modest_mail_operation_update_account (ModestMailOperation *self,
 
        /* Create the helper object */
        info = g_slice_new (UpdateAccountInfo);
-       info->mail_op = g_object_ref (self);
+       info->mail_op = self;
        info->account = modest_account;
-       info->user_data = NULL;
+       info->transport_account = transport_account;
 
        thread = g_thread_create (update_account_thread, info, FALSE, NULL);
 
@@ -800,8 +864,18 @@ modest_mail_operation_rename_folder (ModestMailOperation *self,
                             _("FIXME: unable to rename"));
        } else {
                /* Rename. Camel handles folder subscription/unsubscription */
-               tny_folder_set_name (folder, name, &(priv->error));
+               TnyFolderStore *into;
+               TnyFolder *nfol;
+
+               into = tny_folder_get_folder_store (folder);
+               nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
+               if (into)
+                       g_object_unref (into);
+               if (nfol)
+                       g_object_unref (nfol);
+
                CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
+               
        }
 
        /* Notify the queue */
@@ -843,7 +917,7 @@ transfer_folder_status_cb (GObject *obj,
 
 
 static void
-transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, const gchar *new_name, gboolean cancelled, GError **err, gpointer user_data)
+transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
 {
        XFerFolderAsyncHelper *helper = NULL;
        ModestMailOperation *self = NULL;
@@ -861,18 +935,20 @@ transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, const gchar *new_na
        } 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"),
+                            MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
+                            _("Transference of %s was cancelled."),
                             tny_folder_get_name (folder));
        } else {
                priv->done = 1;
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
-
+               
        /* Free */
        g_slice_free   (XFerFolderAsyncHelper, helper);
        g_object_unref (folder);
        g_object_unref (into);
+       if (new_folder != NULL) 
+               g_object_unref (new_folder);
 
        /* Notify the queue */
        modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
@@ -931,6 +1007,10 @@ modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
 
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
 
+       /* Pick references for async calls */
+       g_object_ref (folder);
+       g_object_ref (parent);
+
        /* The moveable restriction is applied also to copy operation */
        rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
        if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
@@ -957,10 +1037,10 @@ modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
 /* **************************  MSG  ACTIONS  ************************* */
 /* ******************************************************************* */
 
-void          modest_mail_operation_get_msg     (ModestMailOperation *self,
-                                                TnyHeader *header,
-                                                GetMsgAsynUserCallback user_callback,
-                                                gpointer user_data)
+void modest_mail_operation_get_msg (ModestMailOperation *self,
+                                   TnyHeader *header,
+                                   GetMsgAsynUserCallback user_callback,
+                                   gpointer user_data)
 {
        GetMsgAsyncHelper *helper = NULL;
        TnyFolder *folder;
@@ -1077,95 +1157,218 @@ get_msg_status_cb (GObject *obj,
        g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
 }
 
+/****************************************************/
+typedef struct {
+       ModestMailOperation *mail_op;
+       TnyList *headers;
+       GetMsgAsynUserCallback user_callback;
+       gpointer user_data;
+       GDestroyNotify notify;
+} GetFullMsgsInfo;
 
-void          modest_mail_operation_process_msg     (ModestMailOperation *self,
-                                                    TnyList *header_list, 
-                                                    GetMsgAsynUserCallback user_callback,
-                                                    gpointer user_data)
+/* 
+ * Used by get_msgs_full_thread to emit the "progress-changed" signal
+ * from the main loop. We call it inside an idle call to achieve that
+ */
+static gboolean
+notify_get_msgs_full_observers (gpointer data)
 {
+       ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
+
+       g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
+
+       g_object_unref (mail_op);
+
+       return FALSE;
+}
+
+typedef struct {
+       GetMsgAsynUserCallback user_callback;
+       TnyMsg *msg;
+       gpointer user_data;
+       GObject *source;
+} NotifyGetMsgsInfo;
+
+
+/* 
+ * Used by get_msgs_full_thread to call the user_callback for each
+ * message that has been read
+ */
+static gboolean
+notify_get_msgs_full (gpointer data)
+{
+       NotifyGetMsgsInfo *info;
+
+       info = (NotifyGetMsgsInfo *) data;      
+
+       /* Call the user callback */
+       info->user_callback (info->source, info->msg, info->user_data);
+
+       g_slice_free (NotifyGetMsgsInfo, info);
+
+       return FALSE;
+}
+
+/* 
+ * Used by get_msgs_full_thread to free al the thread resources and to
+ * call the destroy function for the passed user_data
+ */
+static gboolean
+get_msgs_full_destroyer (gpointer data)
+{
+       GetFullMsgsInfo *info;
+
+       info = (GetFullMsgsInfo *) data;
+
+       if (info->notify)
+               info->notify (info->user_data);
+
+       /* free */
+       g_object_unref (info->headers);
+       g_slice_free (GetFullMsgsInfo, info);
+
+       return FALSE;
+}
+
+static gpointer
+get_msgs_full_thread (gpointer thr_user_data)
+{
+       GetFullMsgsInfo *info;
        ModestMailOperationPrivate *priv = NULL;
-       GetMsgAsyncHelper *helper = NULL;
-       TnyHeader *header = NULL;
-       TnyFolder *folder = NULL;
        TnyIterator *iter = NULL;
        
-       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
-       
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
-       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
-
-       iter = tny_list_create_iterator (header_list); 
-       priv->done = 1;
-       priv->total = tny_list_get_length(header_list);
-
-       helper = g_slice_new0 (GetMsgAsyncHelper);
-       helper->mail_op = self;
-       helper->user_callback = user_callback;
-       helper->pending_ops = priv->total;
-       helper->user_data = user_data;
+       info = (GetFullMsgsInfo *) thr_user_data;       
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
 
+       iter = tny_list_create_iterator (info->headers);
        while (!tny_iterator_is_done (iter)) { 
+               TnyHeader *header;
+               TnyFolder *folder;
                
-               header = TNY_HEADER (tny_iterator_get_current (iter));          
+               header = TNY_HEADER (tny_iterator_get_current (iter));
                folder = tny_header_get_folder (header);
                                
                /* Get message from folder */
                if (folder) {
+                       TnyMsg *msg;
                        /* The callback will call it per each header */
-                       tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
-                       g_object_unref (G_OBJECT (folder));
-               } else {                        
+                       msg = tny_folder_get_msg (folder, header, &(priv->error));
+
+                       if (msg) {
+                               priv->done++;
+
+                               /* notify progress */
+                               g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+                                                notify_get_msgs_full_observers, 
+                                                g_object_ref (info->mail_op), NULL);
+
+                               /* The callback is the responsible for
+                                  freeing the message */
+                               if (info->user_callback) {
+                                       NotifyGetMsgsInfo *info_notify;
+                                       info_notify = g_slice_new0 (NotifyGetMsgsInfo);
+                                       info_notify->user_callback = info->user_callback;
+                                       info_notify->source = priv->source;
+                                       info_notify->msg = msg;
+                                       info_notify->user_data = info->user_data;
+                                       g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+                                                        notify_get_msgs_full, 
+                                                        info_notify, NULL);
+                               } else {
+                                       g_object_unref (msg);
+                               }
+                       }
+               } else {
                        /* 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_ITEM_NOT_FOUND,
-                                    _("Error trying to get a message. No folder found for header"));
-
-                       /* Notify the queue */
-                       modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
-
-                       /* free */
-                       g_slice_free (GetMsgAsyncHelper, helper);
-                       break;
+                                    "Error trying to get a message. No folder found for header");
                }
-
                g_object_unref (header);                
                tny_iterator_next (iter);
        }
-}
 
-static void     
-update_process_msg_status_cb (GObject *obj,
-                             TnyStatus *status,  
-                             gpointer user_data)
-{
-       GetMsgAsyncHelper *helper = NULL;
-       ModestMailOperation *self;
-       ModestMailOperationPrivate *priv;
+       /* Notify the queue */
+       g_idle_add (notify_update_account_queue, info->mail_op);
 
-       g_return_if_fail (status != NULL);
-       g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
+       /* 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);
 
-       helper = (GetMsgAsyncHelper *) user_data;
-       g_return_if_fail (helper != NULL);       
+       return NULL;
+}
 
-       /* Temporary FIX: useful when tinymail send us status
-          information *after* calling the function callback */
-       if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
-               return;
+void 
+modest_mail_operation_get_msgs_full (ModestMailOperation *self,
+                                    TnyList *header_list, 
+                                    GetMsgAsynUserCallback user_callback,
+                                    gpointer user_data,
+                                    GDestroyNotify notify)
+{
+       GThread *thread;
+       ModestMailOperationPrivate *priv = NULL;
+       GetFullMsgsInfo *info = NULL;
+       gboolean size_ok = TRUE;
+       gint max_size;
+       GError *error = NULL;
+       const gint KB = 1024;
+       
+       g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
+       
+       /* Init mail operation */
+       priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
+       priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
+       priv->done = 0;
+       priv->total = tny_list_get_length(header_list);
 
-       self = helper->mail_op;
-       priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
+       /* Get msg size limit */
+       max_size  = modest_conf_get_int (modest_runtime_get_conf (), 
+                                        MODEST_CONF_MSG_SIZE_LIMIT, 
+                                        &error);
+       if (error) {
+               g_clear_error (&error);
+               max_size = G_MAXINT;
+       } else {
+               max_size = max_size * KB;
+       }
 
-       if ((status->position == 1) && (status->of_total == 100))
-               return;
+       /* Check message size limits. If there is only one message
+          always retrieve it */
+       if (tny_list_get_length (header_list) > 1) {
+               TnyIterator *iter;
 
-       if (status->of_total > 0)
-               priv->done += status->position/status->of_total;
+               iter = tny_list_create_iterator (header_list);
+               while (!tny_iterator_is_done (iter) && size_ok) {
+                       TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
+                       if (tny_header_get_message_size (header) >= max_size)
+                               size_ok = FALSE;
+                       g_object_unref (header);
+                       tny_iterator_next (iter);
+               }
+               g_object_unref (iter);
+       }
 
-       g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
-}
+       if (size_ok) {
+               /* Create the info */
+               info = g_slice_new0 (GetFullMsgsInfo);
+               info->mail_op = self;
+               info->user_callback = user_callback;
+               info->user_data = user_data;
+               info->headers = g_object_ref (header_list);
+               info->notify = notify;
 
+               thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
+       } else {
+               /* FIXME: the error msg is different for pop */
+               g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
+                            MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
+                            _("emev_ni_ui_imap_msg_sizelimit_error"));
+               /* Remove from queue and free resources */
+               modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
+               if (notify)
+                       notify (user_data);
+       }
+}
 
 
 void 
@@ -1201,7 +1404,7 @@ modest_mail_operation_remove_msg (ModestMailOperation *self,
                        g_object_unref (header);
 
                        /* Move to trash */
-                       modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
+                       modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
                        g_object_unref (headers);
 /*                     g_object_unref (trash_folder); */
                } else {
@@ -1295,10 +1498,15 @@ transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer
                priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
        }
 
+       /* If user defined callback function was defined, call it */
+       if (helper->user_callback) {
+               helper->user_callback (priv->source, helper->user_data);
+       }
+
        /* Free */
-/*     g_object_unref (helper->headers); */
-/*     g_object_unref (helper->dest_folder); */
-/*     g_object_unref (helper->mail_op); */
+       g_object_unref (helper->headers);
+       g_object_unref (helper->dest_folder);
+       g_object_unref (helper->mail_op);
        g_slice_free   (XFerMsgAsyncHelper, helper);
        g_object_unref (folder);
 
@@ -1310,7 +1518,9 @@ void
 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
                                 TnyList *headers, 
                                 TnyFolder *folder, 
-                                gboolean delete_original)
+                                gboolean delete_original,
+                                XferMsgsAsynUserCallback user_callback,
+                                gpointer user_data)
 {
        ModestMailOperationPrivate *priv;
        TnyIterator *iter;
@@ -1322,9 +1532,6 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
        g_return_if_fail (TNY_IS_LIST (headers));
        g_return_if_fail (TNY_IS_FOLDER (folder));
 
-       /* Pick references for async calls */
-       g_object_ref (folder);
-
        priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
        priv->total = 1;
        priv->done = 0;
@@ -1332,9 +1539,11 @@ modest_mail_operation_xfer_msgs (ModestMailOperation *self,
 
        /* Create the helper */
        helper = g_slice_new0 (XFerMsgAsyncHelper);
-       helper->mail_op = self;
+       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;
 
        /* Get source folder */
        iter = tny_list_create_iterator (headers);