* Added asynchronous account update
[modest] / src / modest-mail-operation.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
32 #include <string.h>
33 #include <stdarg.h>
34 #include <tny-mime-part.h>
35 #include <tny-store-account.h>
36 #include <tny-folder-store.h>
37 #include <tny-folder-store-query.h>
38 #include <tny-camel-stream.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include <modest-tny-account.h>
45 #include <modest-tny-send-queue.h>
46 #include <modest-runtime.h>
47 #include "modest-text-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-folder.h"
50 #include "modest-tny-platform-factory.h"
51 #include "modest-marshal.h"
52 #include "modest-error.h"
53
54 /* 'private'/'protected' functions */
55 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
56 static void modest_mail_operation_init       (ModestMailOperation *obj);
57 static void modest_mail_operation_finalize   (GObject *obj);
58
59 static void     update_process_msg_status_cb (GObject *obj,
60                                               TnyStatus *status,  
61                                               gpointer user_data);
62 static void     get_msg_cb (TnyFolder *folder, 
63                             gboolean cancelled, 
64                             TnyMsg *msg, 
65                             GError **err, 
66                             gpointer user_data);
67
68 static void     get_msg_status_cb (GObject *obj,
69                                    TnyStatus *status,  
70                                    gpointer user_data);
71
72
73 enum _ModestMailOperationSignals 
74 {
75         PROGRESS_CHANGED_SIGNAL,
76
77         NUM_SIGNALS
78 };
79
80 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
81 struct _ModestMailOperationPrivate {
82         guint                      done;
83         guint                      total;
84         ModestMailOperationStatus  status;      
85         ModestMailOperationId      id;          
86         GObject                   *source;
87         GError                    *error;
88 };
89
90 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
91                                                    MODEST_TYPE_MAIL_OPERATION, \
92                                                    ModestMailOperationPrivate))
93
94 #define CHECK_EXCEPTION(priv, new_status)  if (priv->error) {\
95                                                    priv->status = new_status;\
96                                                }
97
98 typedef struct _GetMsgAsyncHelper {     
99         ModestMailOperation *mail_op;
100         GetMsgAsynUserCallback user_callback;   
101         guint pending_ops;
102         gpointer user_data;
103 } GetMsgAsyncHelper;
104
105 typedef struct _RefreshFolderAsyncHelper
106 {
107         ModestMailOperation *mail_op;
108         TnyIterator *iter;
109         guint failed;
110         guint canceled;
111
112 } RefreshFolderAsyncHelper;
113
114 typedef struct _XFerMsgAsyncHelper
115 {
116         ModestMailOperation *mail_op;
117         TnyList *headers;
118         TnyFolder *dest_folder;
119
120 } XFerMsgAsyncHelper;
121
122 typedef struct _XFerFolderAsyncHelper
123 {
124         ModestMailOperation *mail_op;
125
126 } XFerFolderAsyncHelper;
127
128
129 /* globals */
130 static GObjectClass *parent_class = NULL;
131
132 static guint signals[NUM_SIGNALS] = {0};
133
134 GType
135 modest_mail_operation_get_type (void)
136 {
137         static GType my_type = 0;
138         if (!my_type) {
139                 static const GTypeInfo my_info = {
140                         sizeof(ModestMailOperationClass),
141                         NULL,           /* base init */
142                         NULL,           /* base finalize */
143                         (GClassInitFunc) modest_mail_operation_class_init,
144                         NULL,           /* class finalize */
145                         NULL,           /* class data */
146                         sizeof(ModestMailOperation),
147                         1,              /* n_preallocs */
148                         (GInstanceInitFunc) modest_mail_operation_init,
149                         NULL
150                 };
151                 my_type = g_type_register_static (G_TYPE_OBJECT,
152                                                   "ModestMailOperation",
153                                                   &my_info, 0);
154         }
155         return my_type;
156 }
157
158 static void
159 modest_mail_operation_class_init (ModestMailOperationClass *klass)
160 {
161         GObjectClass *gobject_class;
162         gobject_class = (GObjectClass*) klass;
163
164         parent_class            = g_type_class_peek_parent (klass);
165         gobject_class->finalize = modest_mail_operation_finalize;
166
167         g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
168
169         /**
170          * ModestMailOperation::progress-changed
171          * @self: the #MailOperation that emits the signal
172          * @user_data: user data set when the signal handler was connected
173          *
174          * Emitted when the progress of a mail operation changes
175          */
176         signals[PROGRESS_CHANGED_SIGNAL] = 
177                 g_signal_new ("progress-changed",
178                               G_TYPE_FROM_CLASS (gobject_class),
179                               G_SIGNAL_RUN_FIRST,
180                               G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
181                               NULL, NULL,
182                               g_cclosure_marshal_VOID__VOID,
183                               G_TYPE_NONE, 0);
184 }
185
186 static void
187 modest_mail_operation_init (ModestMailOperation *obj)
188 {
189         ModestMailOperationPrivate *priv;
190
191         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
192
193         priv->status   = MODEST_MAIL_OPERATION_STATUS_INVALID;
194         priv->id       = MODEST_MAIL_OPERATION_ID_UNKNOWN;
195         priv->error    = NULL;
196         priv->done     = 0;
197         priv->total    = 0;
198         priv->source = NULL;
199 }
200
201 static void
202 modest_mail_operation_finalize (GObject *obj)
203 {
204         ModestMailOperationPrivate *priv;
205
206         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
207
208         if (priv->error) {
209                 g_error_free (priv->error);
210                 priv->error = NULL;
211         }
212         if (priv->source) {
213                 g_object_unref (priv->source);
214                 priv->source = NULL;
215         }
216
217         G_OBJECT_CLASS(parent_class)->finalize (obj);
218 }
219
220 ModestMailOperation*
221 modest_mail_operation_new (ModestMailOperationId id, 
222                            GObject *source)
223 {
224         ModestMailOperation *obj;
225         ModestMailOperationPrivate *priv;
226                 
227         obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
228         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
229
230         priv->id = id;
231         if (source != NULL)
232                 priv->source = g_object_ref(source);
233
234         return obj;
235 }
236
237
238 ModestMailOperationId
239 modest_mail_operation_get_id (ModestMailOperation *self)
240 {
241         ModestMailOperationPrivate *priv;
242
243         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
244         
245         return priv->id;
246 }
247
248 gboolean 
249 modest_mail_operation_is_mine (ModestMailOperation *self, 
250                                GObject *me)
251 {
252         ModestMailOperationPrivate *priv;
253
254         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
255         if (priv->source == NULL) return FALSE;
256
257         return priv->source == me;
258 }
259
260
261 void
262 modest_mail_operation_send_mail (ModestMailOperation *self,
263                                  TnyTransportAccount *transport_account,
264                                  TnyMsg* msg)
265 {
266         TnySendQueue *send_queue;
267         
268         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
269         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
270         g_return_if_fail (TNY_IS_MSG (msg));
271         
272         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
273         if (!TNY_IS_SEND_QUEUE(send_queue))
274                 g_printerr ("modest: could not find send queue for account\n");
275         else {
276                 GError *err = NULL;
277                 tny_send_queue_add (send_queue, msg, &err);
278                 if (err) {
279                         g_printerr ("modest: error adding msg to send queue: %s\n",
280                                     err->message);
281                         g_error_free (err);
282                 } else {
283                         /* g_message ("modest: message added to send queue"); */
284                 }
285         }
286
287         /* Notify the queue */
288         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
289 }
290
291 void
292 modest_mail_operation_send_new_mail (ModestMailOperation *self,
293                                      TnyTransportAccount *transport_account,
294                                      const gchar *from,  const gchar *to,
295                                      const gchar *cc,  const gchar *bcc,
296                                      const gchar *subject, const gchar *plain_body,
297                                      const gchar *html_body,
298                                      const GList *attachments_list,
299                                      TnyHeaderFlags priority_flags)
300 {
301         TnyMsg *new_msg;
302         ModestMailOperationPrivate *priv = NULL;
303         /* GList *node = NULL; */
304
305         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
306         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
307
308         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
309
310         /* Check parametters */
311         if (to == NULL) {
312                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
313                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
314                              _("Error trying to send a mail. You need to set at least one recipient"));
315                 return;
316         }
317
318         if (html_body == NULL) {
319                 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
320         } else {
321                 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
322         }
323         if (!new_msg) {
324                 g_printerr ("modest: failed to create a new msg\n");
325                 return;
326         }
327
328         /* TODO: add priority handling. It's received in the priority_flags operator, and
329            it should have effect in the sending operation */
330
331         /* Call mail operation */
332         modest_mail_operation_send_mail (self, transport_account, new_msg);
333
334         /* Free */
335         g_object_unref (G_OBJECT (new_msg));
336 }
337
338 void
339 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
340                                       TnyTransportAccount *transport_account,
341                                       const gchar *from,  const gchar *to,
342                                       const gchar *cc,  const gchar *bcc,
343                                       const gchar *subject, const gchar *plain_body,
344                                       const gchar *html_body,
345                                       const GList *attachments_list,
346                                       TnyHeaderFlags priority_flags)
347 {
348         TnyMsg *msg = NULL;
349         TnyFolder *folder = NULL;
350         ModestMailOperationPrivate *priv = NULL;
351         GError *err = NULL;
352
353         /* GList *node = NULL; */
354
355         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
356         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
357
358         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
359
360         if (html_body == NULL) {
361                 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
362         } else {
363                 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
364         }
365         if (!msg) {
366                 g_printerr ("modest: failed to create a new msg\n");
367                 goto cleanup;
368         }
369
370         folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
371         if (!folder) {
372                 g_printerr ("modest: failed to find Drafts folder\n");
373                 goto cleanup;
374         }
375         
376         tny_folder_add_msg (folder, msg, &err);
377         if (err) {
378                 g_printerr ("modest: error adding msg to Drafts folder: %s",
379                             err->message);
380                 g_error_free (err);
381                 goto cleanup;
382         }
383
384         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
385
386         /* Free */
387 cleanup:
388         if (msg)
389                 g_object_unref (G_OBJECT(msg));
390         if (folder)
391                 g_object_unref (G_OBJECT(folder));
392 }
393
394 typedef struct 
395 {
396         ModestMailOperation *mail_op;
397         TnyStoreAccount *account;
398         gpointer user_data;
399 } UpdateAccountInfo;
400
401 static void
402 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
403 {
404         TnyIterator *iter;
405         TnyList *folders = tny_simple_list_new ();
406
407         tny_folder_store_get_folders (store, folders, query, NULL);
408         iter = tny_list_create_iterator (folders);
409
410         while (!tny_iterator_is_done (iter)) {
411
412                 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
413
414                 tny_list_prepend (all_folders, G_OBJECT (folder));
415                 recurse_folders (folder, query, all_folders);    
416                 g_object_unref (G_OBJECT (folder));
417
418                 tny_iterator_next (iter);
419         }
420          g_object_unref (G_OBJECT (iter));
421          g_object_unref (G_OBJECT (folders));
422 }
423
424 /* 
425  * Used by update_account_thread to emit the signal from the main
426  * loop. We call it inside an idle call to achieve that 
427  */
428 static gboolean
429 notify_update_account_observers (gpointer data)
430 {
431         ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
432
433         g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
434         g_object_unref (mail_op);
435
436         return FALSE;
437 }
438
439 /* 
440  * Used by update_account_thread to notify the queue from the main
441  * loop. We call it inside an idle call to achieve that
442  */
443 static gboolean
444 notify_update_account_queue (gpointer data)
445 {
446         ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
447
448         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
449                                             mail_op);
450         g_object_unref (mail_op);
451
452         return FALSE;
453 }
454
455 static gpointer
456 update_account_thread (gpointer thr_user_data)
457 {
458         UpdateAccountInfo *info;
459         TnyList *all_folders = NULL;
460         TnyIterator *iter = NULL;
461         TnyFolderStoreQuery *query = NULL;
462         ModestMailOperationPrivate *priv;
463
464         info = (UpdateAccountInfo *) thr_user_data;
465         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
466
467         /* Get all the folders We can do it synchronously because
468            we're already running in a different thread than the UI */
469         all_folders = tny_simple_list_new ();
470         query = tny_folder_store_query_new ();
471         tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
472         tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
473                                       all_folders,
474                                       query,
475                                       &(priv->error));
476         if (priv->error) {
477                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
478                 goto out;
479         }
480
481         iter = tny_list_create_iterator (all_folders);
482         while (!tny_iterator_is_done (iter)) {
483                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
484
485                 recurse_folders (folder, query, all_folders);
486                 tny_iterator_next (iter);
487         }
488         g_object_unref (G_OBJECT (iter));
489
490         priv->total = tny_list_get_length (all_folders);
491         priv->done = 0;
492
493         /* Refresh folders */
494         iter = tny_list_create_iterator (all_folders);
495         while (!tny_iterator_is_done (iter) && !priv->error) {
496
497                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
498
499                 /* Refresh the folder */
500                 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
501                 priv->done++;
502
503                 if (priv->error) {
504                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
505                 } else {
506                         /* Update status and notify. We need to call
507                            the notification with an idle in order to
508                            call it from the main loop. We need that in
509                            order not to get into trouble with Gtk+ */
510                         priv->done++;
511                         g_idle_add (notify_update_account_observers, g_object_ref (info->mail_op));
512                 }
513
514                 g_object_unref (G_OBJECT (folder));
515                 tny_iterator_next (iter);
516         }
517         g_object_unref (G_OBJECT (iter));
518
519         /* Check if the operation was a success */
520         if (priv->done == priv->total && !priv->error)
521                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
522
523  out:
524         /* Notify the queue */
525         g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
526
527         /* Frees */
528         g_object_unref (query);
529         g_object_unref (all_folders);
530         g_object_unref (info->mail_op);
531         g_object_unref (info->account);
532         g_slice_free (UpdateAccountInfo, info);
533
534         return NULL;
535 }
536
537 gboolean
538 modest_mail_operation_update_account (ModestMailOperation *self,
539                                       TnyStoreAccount *store_account)
540 {
541         GThread *thread;
542         UpdateAccountInfo *info;
543         ModestMailOperationPrivate *priv;
544
545         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
546         g_return_val_if_fail (TNY_IS_STORE_ACCOUNT(store_account), FALSE);
547
548         /* Init mail operation */
549         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
550         priv->total = 0;
551         priv->done  = 0;
552         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
553         
554         /* Create the helper object */
555         info = g_slice_new (UpdateAccountInfo);
556         info->mail_op = g_object_ref (self);
557         info->account = g_object_ref (store_account);
558         info->user_data = NULL;
559
560         thread = g_thread_create (update_account_thread, info, FALSE, NULL);
561
562         return TRUE;
563 }
564
565 ModestMailOperationStatus
566 modest_mail_operation_get_status (ModestMailOperation *self)
567 {
568         ModestMailOperationPrivate *priv;
569
570         g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
571         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
572                               MODEST_MAIL_OPERATION_STATUS_INVALID);
573
574         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
575         return priv->status;
576 }
577
578 const GError *
579 modest_mail_operation_get_error (ModestMailOperation *self)
580 {
581         ModestMailOperationPrivate *priv;
582
583         g_return_val_if_fail (self, NULL);
584         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
585
586         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
587         return priv->error;
588 }
589
590 gboolean 
591 modest_mail_operation_cancel (ModestMailOperation *self)
592 {
593         ModestMailOperationPrivate *priv;
594
595         if (!MODEST_IS_MAIL_OPERATION (self)) {
596                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
597                 return FALSE;
598         }
599
600         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
601
602         /* TODO: Tinymail does not support cancel operation  */
603         
604         /* Set new status */
605         priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
606
607         /* Notify the queue */
608         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
609
610         return TRUE;
611 }
612
613 guint 
614 modest_mail_operation_get_task_done (ModestMailOperation *self)
615 {
616         ModestMailOperationPrivate *priv;
617
618         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
619
620         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
621         return priv->done;
622 }
623
624 guint 
625 modest_mail_operation_get_task_total (ModestMailOperation *self)
626 {
627         ModestMailOperationPrivate *priv;
628
629         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
630
631         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
632         return priv->total;
633 }
634
635 gboolean
636 modest_mail_operation_is_finished (ModestMailOperation *self)
637 {
638         ModestMailOperationPrivate *priv;
639         gboolean retval = FALSE;
640
641         if (!MODEST_IS_MAIL_OPERATION (self)) {
642                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
643                 return retval;
644         }
645
646         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
647
648         if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS   ||
649             priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED    ||
650             priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED  ||
651             priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
652                 retval = TRUE;
653         } else {
654                 retval = FALSE;
655         }
656
657         return retval;
658 }
659
660 /* ******************************************************************* */
661 /* ************************** STORE  ACTIONS ************************* */
662 /* ******************************************************************* */
663
664
665 TnyFolder *
666 modest_mail_operation_create_folder (ModestMailOperation *self,
667                                      TnyFolderStore *parent,
668                                      const gchar *name)
669 {
670         ModestTnyFolderRules rules;
671         ModestMailOperationPrivate *priv;
672         TnyFolder *new_folder = NULL;
673         gboolean can_create = FALSE;
674
675         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
676         g_return_val_if_fail (name, NULL);
677         
678         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
679
680         /* Check parent */
681         if (!TNY_IS_FOLDER (parent)) {
682                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
683                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
684                              _("mail_in_ui_folder_create_error"));
685         } else {
686                 /* Check folder rules */
687                 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
688                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
689                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
690                                      MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
691                                      _("mail_in_ui_folder_create_error"));
692                 else
693                         can_create = TRUE;              
694         }
695
696         if (can_create) {
697                 /* Create the folder */
698                 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
699                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
700         }
701
702         /* Notify the queue */
703         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
704
705         return new_folder;
706 }
707
708 void
709 modest_mail_operation_remove_folder (ModestMailOperation *self,
710                                      TnyFolder           *folder,
711                                      gboolean             remove_to_trash)
712 {
713         TnyAccount *account;
714         ModestMailOperationPrivate *priv;
715         ModestTnyFolderRules rules;
716
717         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
718         g_return_if_fail (TNY_IS_FOLDER (folder));
719         
720         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
721         
722         /* Check folder rules */
723         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
724         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
725                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
726                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
727                              _("mail_in_ui_folder_delete_error"));
728                 goto end;
729         }
730
731         /* Get the account */
732         account = tny_folder_get_account (folder);
733
734         /* Delete folder or move to trash */
735         if (remove_to_trash) {
736                 TnyFolder *trash_folder = NULL;
737 /*              TnyFolder *trash_folder, *new_folder; */
738                 trash_folder = modest_tny_account_get_special_folder (account,
739                                                                       TNY_FOLDER_TYPE_TRASH);
740                 /* TODO: error_handling */
741                  modest_mail_operation_xfer_folder (self, folder,
742                                                     TNY_FOLDER_STORE (trash_folder), TRUE);
743 /*              new_folder = modest_mail_operation_xfer_folder (self, folder,  */
744 /*                                                              TNY_FOLDER_STORE (trash_folder), TRUE); */
745 /*              g_object_unref (G_OBJECT (new_folder)); */
746         } else {
747                 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
748
749                 tny_folder_store_remove_folder (parent, folder, &(priv->error));
750                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
751
752                 if (parent)
753                         g_object_unref (G_OBJECT (parent));
754         }
755         g_object_unref (G_OBJECT (account));
756
757  end:
758         /* Notify the queue */
759         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
760 }
761
762 void
763 modest_mail_operation_rename_folder (ModestMailOperation *self,
764                                      TnyFolder *folder,
765                                      const gchar *name)
766 {
767         ModestMailOperationPrivate *priv;
768         ModestTnyFolderRules rules;
769
770         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
771         g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
772         g_return_if_fail (name);
773         
774         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
775
776         /* Check folder rules */
777         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
778         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
779                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
780                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
781                              _("FIXME: unable to rename"));
782         } else {
783                 /* Rename. Camel handles folder subscription/unsubscription */
784                 tny_folder_set_name (folder, name, &(priv->error));
785                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
786         }
787
788         /* Notify the queue */
789         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
790  }
791
792 static void
793 transfer_folder_status_cb (GObject *obj,
794                            TnyStatus *status,  
795                            gpointer user_data)
796 {
797         XFerMsgAsyncHelper *helper = NULL;
798         ModestMailOperation *self;
799         ModestMailOperationPrivate *priv;
800
801         g_return_if_fail (status != NULL);
802         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
803
804         helper = (XFerMsgAsyncHelper *) user_data;
805         g_return_if_fail (helper != NULL);       
806
807         /* Temporary FIX: useful when tinymail send us status
808            information *after* calling the function callback */
809         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
810                 return;
811
812         self = helper->mail_op;
813         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
814
815         if ((status->position == 1) && (status->of_total == 100))
816                 return;
817
818         priv->done = status->position;
819         priv->total = status->of_total;
820
821
822         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
823 }
824
825
826 static void
827 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, const gchar *new_name, gboolean cancelled, GError **err, gpointer user_data)
828 {
829         XFerFolderAsyncHelper *helper = NULL;
830         ModestMailOperation *self = NULL;
831         ModestMailOperationPrivate *priv = NULL;
832
833         helper = (XFerFolderAsyncHelper *) user_data;
834         self = helper->mail_op;
835
836         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
837
838         if (*err) {
839                 priv->error = g_error_copy (*err);
840                 priv->done = 0;
841                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
842         } else if (cancelled) {
843                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
844                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
845                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
846                              _("Error trying to refresh the contents of %s"),
847                              tny_folder_get_name (folder));
848         } else {
849                 priv->done = 1;
850                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
851         }
852
853         /* Free */
854         g_slice_free   (XFerFolderAsyncHelper, helper);
855         g_object_unref (folder);
856         g_object_unref (into);
857
858         /* Notify the queue */
859         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
860 }
861
862 TnyFolder *
863 modest_mail_operation_xfer_folder (ModestMailOperation *self,
864                                    TnyFolder *folder,
865                                    TnyFolderStore *parent,
866                                    gboolean delete_original)
867 {
868         ModestMailOperationPrivate *priv;
869         TnyFolder *new_folder = NULL;
870         ModestTnyFolderRules rules;
871
872         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
873         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
874         g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
875
876         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
877
878         /* The moveable restriction is applied also to copy operation */
879         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
880         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
881                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
882                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
883                              _("FIXME: unable to rename"));
884         } else {
885                 /* Move/Copy folder */
886                 new_folder = tny_folder_copy (folder,
887                                               parent,
888                                               tny_folder_get_name (folder),
889                                               delete_original,
890                                               &(priv->error));
891         }
892
893         /* Notify the queue */
894         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
895
896         return new_folder;
897 }
898
899 void
900 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
901                                          TnyFolder *folder,
902                                          TnyFolderStore *parent,
903                                          gboolean delete_original)
904 {
905         XFerFolderAsyncHelper *helper = NULL;
906         ModestMailOperationPrivate *priv = NULL;
907         ModestTnyFolderRules rules;
908
909         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
910         g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
911         g_return_if_fail (TNY_IS_FOLDER (folder));
912
913         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
914
915         /* The moveable restriction is applied also to copy operation */
916         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
917         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
918                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
919                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
920                              _("FIXME: unable to rename"));
921         } else {
922                 helper = g_slice_new0 (XFerFolderAsyncHelper);
923                 helper->mail_op = self;
924
925                 /* Move/Copy folder */          
926                 tny_folder_copy_async (folder,
927                                        parent,
928                                        tny_folder_get_name (folder),
929                                        delete_original,
930                                        transfer_folder_cb,
931                                        transfer_folder_status_cb,
932                                        helper);
933         }
934 }
935
936
937 /* ******************************************************************* */
938 /* **************************  MSG  ACTIONS  ************************* */
939 /* ******************************************************************* */
940
941 void          modest_mail_operation_get_msg     (ModestMailOperation *self,
942                                                  TnyHeader *header,
943                                                  GetMsgAsynUserCallback user_callback,
944                                                  gpointer user_data)
945 {
946         GetMsgAsyncHelper *helper = NULL;
947         TnyFolder *folder;
948         ModestMailOperationPrivate *priv;
949         
950         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
951         g_return_if_fail (TNY_IS_HEADER (header));
952         
953         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
954         folder = tny_header_get_folder (header);
955
956         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
957
958         /* Get message from folder */
959         if (folder) {
960                 helper = g_slice_new0 (GetMsgAsyncHelper);
961                 helper->mail_op = self;
962                 helper->user_callback = user_callback;
963                 helper->pending_ops = 1;
964                 helper->user_data = user_data;
965
966                 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
967
968                 g_object_unref (G_OBJECT (folder));
969         } else {
970                 /* Set status failed and set an error */
971                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
972                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
973                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
974                              _("Error trying to get a message. No folder found for header"));
975         }
976 }
977
978 static void
979 get_msg_cb (TnyFolder *folder, 
980             gboolean cancelled, 
981             TnyMsg *msg, 
982             GError **error, 
983             gpointer user_data)
984 {
985         GetMsgAsyncHelper *helper = NULL;
986         ModestMailOperation *self = NULL;
987         ModestMailOperationPrivate *priv = NULL;
988
989         helper = (GetMsgAsyncHelper *) user_data;
990         g_return_if_fail (helper != NULL);       
991         self = helper->mail_op;
992         g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
993         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
994         
995         helper->pending_ops--;
996
997         /* Check errors and cancel */
998         if (*error) {
999                 priv->error = g_error_copy (*error);
1000                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1001                 goto out;
1002         }
1003         if (cancelled) {
1004                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1005                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1006                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1007                              _("Error trying to refresh the contents of %s"),
1008                              tny_folder_get_name (folder));
1009                 goto out;
1010         }
1011
1012         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1013
1014         /* If user defined callback function was defined, call it */
1015         if (helper->user_callback) {
1016                 helper->user_callback (priv->source, msg, helper->user_data);
1017         }
1018
1019         /* Free */
1020  out:
1021         if (helper->pending_ops == 0) {
1022                 g_slice_free (GetMsgAsyncHelper, helper);
1023                 
1024                 /* Notify the queue */
1025                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);  
1026         }
1027 }
1028
1029 static void     
1030 get_msg_status_cb (GObject *obj,
1031                    TnyStatus *status,  
1032                    gpointer user_data)
1033 {
1034         GetMsgAsyncHelper *helper = NULL;
1035         ModestMailOperation *self;
1036         ModestMailOperationPrivate *priv;
1037
1038         g_return_if_fail (status != NULL);
1039         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1040
1041         helper = (GetMsgAsyncHelper *) user_data;
1042         g_return_if_fail (helper != NULL);       
1043
1044         /* Temporary FIX: useful when tinymail send us status
1045            information *after* calling the function callback */
1046         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1047                 return;
1048
1049         self = helper->mail_op;
1050         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1051
1052         if ((status->position == 1) && (status->of_total == 100))
1053                 return;
1054
1055         priv->done = 1;
1056         priv->total = 1;
1057
1058         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1059 }
1060
1061
1062 void          modest_mail_operation_process_msg     (ModestMailOperation *self,
1063                                                      TnyList *header_list, 
1064                                                      GetMsgAsynUserCallback user_callback,
1065                                                      gpointer user_data)
1066 {
1067         ModestMailOperationPrivate *priv = NULL;
1068         GetMsgAsyncHelper *helper = NULL;
1069         TnyHeader *header = NULL;
1070         TnyFolder *folder = NULL;
1071         TnyIterator *iter = NULL;
1072         
1073         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1074         
1075         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1076         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1077
1078         iter = tny_list_create_iterator (header_list); 
1079         priv->done = 1;
1080         priv->total = tny_list_get_length(header_list);
1081
1082         helper = g_slice_new0 (GetMsgAsyncHelper);
1083         helper->mail_op = self;
1084         helper->user_callback = user_callback;
1085         helper->pending_ops = priv->total;
1086         helper->user_data = user_data;
1087
1088         while (!tny_iterator_is_done (iter)) { 
1089                 
1090                 header = TNY_HEADER (tny_iterator_get_current (iter));          
1091                 folder = tny_header_get_folder (header);
1092                                 
1093                 /* Get message from folder */
1094                 if (folder) {
1095                         /* The callback will call it per each header */
1096                         tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1097                         g_object_unref (G_OBJECT (folder));
1098                 } else {                        
1099                         /* Set status failed and set an error */
1100                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1101                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1102                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1103                                      _("Error trying to get a message. No folder found for header"));
1104
1105                         /* Notify the queue */
1106                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1107
1108                         /* free */
1109                         g_slice_free (GetMsgAsyncHelper, helper);
1110                         break;
1111                 }
1112
1113                 g_object_unref (header);                
1114                 tny_iterator_next (iter);
1115         }
1116 }
1117
1118 static void     
1119 update_process_msg_status_cb (GObject *obj,
1120                               TnyStatus *status,  
1121                               gpointer user_data)
1122 {
1123         GetMsgAsyncHelper *helper = NULL;
1124         ModestMailOperation *self;
1125         ModestMailOperationPrivate *priv;
1126
1127         g_return_if_fail (status != NULL);
1128         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1129
1130         helper = (GetMsgAsyncHelper *) user_data;
1131         g_return_if_fail (helper != NULL);       
1132
1133         /* Temporary FIX: useful when tinymail send us status
1134            information *after* calling the function callback */
1135         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1136                 return;
1137
1138         self = helper->mail_op;
1139         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1140
1141         if ((status->position == 1) && (status->of_total == 100))
1142                 return;
1143
1144         if (status->of_total > 0)
1145                 priv->done += status->position/status->of_total;
1146
1147         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1148 }
1149
1150
1151
1152 void 
1153 modest_mail_operation_remove_msg (ModestMailOperation *self,
1154                                   TnyHeader *header,
1155                                   gboolean remove_to_trash)
1156 {
1157         TnyFolder *folder;
1158         ModestMailOperationPrivate *priv;
1159
1160         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1161         g_return_if_fail (TNY_IS_HEADER (header));
1162
1163         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1164         folder = tny_header_get_folder (header);
1165
1166         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1167
1168         /* Delete or move to trash */
1169         if (remove_to_trash) {
1170                 TnyFolder *trash_folder;
1171                 TnyStoreAccount *store_account;
1172
1173                 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1174                 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1175                                                                       TNY_FOLDER_TYPE_TRASH);
1176                 if (trash_folder) {
1177                         TnyList *headers;
1178
1179                         /* Create list */
1180                         headers = tny_simple_list_new ();
1181                         tny_list_append (headers, G_OBJECT (header));
1182                         g_object_unref (header);
1183
1184                         /* Move to trash */
1185                         modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1186                         g_object_unref (headers);
1187 /*                      g_object_unref (trash_folder); */
1188                 } else {
1189                         ModestMailOperationPrivate *priv;
1190
1191                         /* Set status failed and set an error */
1192                         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1193                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1194                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1195                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1196                                      _("Error trying to delete a message. Trash folder not found"));
1197                 }
1198
1199                 g_object_unref (G_OBJECT (store_account));
1200         } else {
1201                 tny_folder_remove_msg (folder, header, &(priv->error));
1202                 if (!priv->error)
1203                         tny_folder_sync(folder, TRUE, &(priv->error));
1204         }
1205
1206         /* Set status */
1207         if (!priv->error)
1208                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1209         else
1210                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1211
1212         /* Free */
1213         g_object_unref (G_OBJECT (folder));
1214
1215         /* Notify the queue */
1216         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1217 }
1218
1219 static void
1220 transfer_msgs_status_cb (GObject *obj,
1221                          TnyStatus *status,  
1222                          gpointer user_data)
1223 {
1224         XFerMsgAsyncHelper *helper = NULL;
1225         ModestMailOperation *self;
1226         ModestMailOperationPrivate *priv;
1227
1228         g_return_if_fail (status != NULL);
1229         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1230
1231         helper = (XFerMsgAsyncHelper *) user_data;
1232         g_return_if_fail (helper != NULL);       
1233
1234         /* Temporary FIX: useful when tinymail send us status
1235            information *after* calling the function callback */
1236         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1237                 return;
1238
1239         self = helper->mail_op;
1240         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1241
1242         if ((status->position == 1) && (status->of_total == 100))
1243                 return;
1244
1245         priv->done = status->position;
1246         priv->total = status->of_total;
1247
1248         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1249 }
1250
1251
1252 static void
1253 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1254 {
1255         XFerMsgAsyncHelper *helper;
1256         ModestMailOperation *self;
1257         ModestMailOperationPrivate *priv;
1258
1259         helper = (XFerMsgAsyncHelper *) user_data;
1260         self = helper->mail_op;
1261
1262         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1263
1264         if (*err) {
1265                 priv->error = g_error_copy (*err);
1266                 priv->done = 0;
1267                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
1268         } else if (cancelled) {
1269                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1270                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1271                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1272                              _("Error trying to refresh the contents of %s"),
1273                              tny_folder_get_name (folder));
1274         } else {
1275                 priv->done = 1;
1276                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1277         }
1278
1279         /* Free */
1280 /*      g_object_unref (helper->headers); */
1281 /*      g_object_unref (helper->dest_folder); */
1282 /*      g_object_unref (helper->mail_op); */
1283         g_slice_free   (XFerMsgAsyncHelper, helper);
1284         g_object_unref (folder);
1285
1286         /* Notify the queue */
1287         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1288 }
1289
1290 void
1291 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1292                                  TnyList *headers, 
1293                                  TnyFolder *folder, 
1294                                  gboolean delete_original)
1295 {
1296         ModestMailOperationPrivate *priv;
1297         TnyIterator *iter;
1298         TnyFolder *src_folder;
1299         XFerMsgAsyncHelper *helper;
1300         TnyHeader *header;
1301
1302         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1303         g_return_if_fail (TNY_IS_LIST (headers));
1304         g_return_if_fail (TNY_IS_FOLDER (folder));
1305
1306         /* Pick references for async calls */
1307         g_object_ref (folder);
1308
1309         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1310         priv->total = 1;
1311         priv->done = 0;
1312         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1313
1314         /* Create the helper */
1315         helper = g_slice_new0 (XFerMsgAsyncHelper);
1316         helper->mail_op = self;
1317         helper->dest_folder = g_object_ref(folder);
1318         helper->headers = g_object_ref(headers);
1319
1320         /* Get source folder */
1321         iter = tny_list_create_iterator (headers);
1322         header = TNY_HEADER (tny_iterator_get_current (iter));
1323         src_folder = tny_header_get_folder (header);
1324         g_object_unref (header);
1325         g_object_unref (iter);
1326
1327         /* Transfer messages */
1328         tny_folder_transfer_msgs_async (src_folder, 
1329                                         headers, 
1330                                         folder, 
1331                                         delete_original, 
1332                                         transfer_msgs_cb, 
1333                                         transfer_msgs_status_cb,
1334                                         helper);
1335 }
1336
1337
1338 static void
1339 on_refresh_folder (TnyFolder   *folder, 
1340                    gboolean     cancelled, 
1341                    GError     **error,
1342                    gpointer     user_data)
1343 {
1344         ModestMailOperation *self;
1345         ModestMailOperationPrivate *priv;
1346
1347         self = MODEST_MAIL_OPERATION (user_data);
1348         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1349
1350         if (*error) {
1351                 priv->error = g_error_copy (*error);
1352                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1353                 goto out;
1354         }
1355
1356         if (cancelled) {
1357                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1358                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1359                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1360                              _("Error trying to refresh the contents of %s"),
1361                              tny_folder_get_name (folder));
1362                 goto out;
1363         }
1364
1365         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1366
1367  out:
1368         /* Free */
1369         g_object_unref (folder);
1370
1371         /* Notify the queue */
1372         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1373 }
1374
1375 static void
1376 on_refresh_folder_status_update (GObject *obj,
1377                                  TnyStatus *status,
1378                                  gpointer user_data)
1379 {
1380         ModestMailOperation *self;
1381         ModestMailOperationPrivate *priv;
1382
1383         g_return_if_fail (status != NULL);
1384         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1385
1386         /* Temporary FIX: useful when tinymail send us status
1387            information *after* calling the function callback */
1388         if (!MODEST_IS_MAIL_OPERATION (user_data))
1389                 return;
1390
1391         self = MODEST_MAIL_OPERATION (user_data);
1392         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1393
1394         priv->done = status->position;
1395         priv->total = status->of_total;
1396
1397         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1398 }
1399
1400 void 
1401 modest_mail_operation_refresh_folder  (ModestMailOperation *self,
1402                                        TnyFolder *folder)
1403 {
1404         ModestMailOperationPrivate *priv;
1405
1406         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1407
1408         /* Pick a reference */
1409         g_object_ref (folder);
1410
1411         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1412
1413         /* Refresh the folder. TODO: tinymail could issue a status
1414            updates before the callback call then this could happen. We
1415            must review the design */
1416         tny_folder_refresh_async (folder,
1417                                   on_refresh_folder,
1418                                   on_refresh_folder_status_update,
1419                                   self);
1420 }
1421
1422 void
1423 _modest_mail_operation_notify_end (ModestMailOperation *self)
1424 {
1425         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1426 }