* fix for compile breakage
[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         TnyTransportAccount *transport_account;
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
435         return TRUE;
436 }
437
438 /* 
439  * Used by update_account_thread to notify the queue from the main
440  * loop. We call it inside an idle call to achieve that
441  */
442 static gboolean
443 notify_update_account_queue (gpointer data)
444 {
445         ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
446
447         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
448                                             mail_op);
449         g_object_unref (mail_op);
450
451         return FALSE;
452 }
453
454 static gpointer
455 update_account_thread (gpointer thr_user_data)
456 {
457         UpdateAccountInfo *info;
458         TnyList *all_folders = NULL;
459         TnyIterator *iter = NULL;
460         TnyFolderStoreQuery *query = NULL;
461         ModestMailOperationPrivate *priv;
462         ModestTnySendQueue *send_queue;
463         gint timeout;
464
465         info = (UpdateAccountInfo *) thr_user_data;
466         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
467
468         /* Get all the folders We can do it synchronously because
469            we're already running in a different thread than the UI */
470         all_folders = tny_simple_list_new ();
471         query = tny_folder_store_query_new ();
472         tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
473         tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
474                                       all_folders,
475                                       query,
476                                       &(priv->error));
477         if (priv->error) {
478                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
479                 goto out;
480         }
481
482         iter = tny_list_create_iterator (all_folders);
483         while (!tny_iterator_is_done (iter)) {
484                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
485
486                 recurse_folders (folder, query, all_folders);
487                 tny_iterator_next (iter);
488         }
489         g_object_unref (G_OBJECT (iter));
490
491         /* Update status and notify. We need to call the notification
492            with a source functopm in order to call it from the main
493            loop. We need that in order not to get into trouble with
494            Gtk+. We use a timeout in order to provide more status
495            information, because the sync tinymail call does not
496            provide it for the moment */
497         timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
498
499         /* Refresh folders */
500         iter = tny_list_create_iterator (all_folders);
501         while (!tny_iterator_is_done (iter) && !priv->error) {
502
503                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
504
505                 /* Refresh the folder */
506                 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
507
508                 if (priv->error) {
509                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
510                 }
511
512                 g_object_unref (G_OBJECT (folder));
513                 tny_iterator_next (iter);
514         }
515         g_object_unref (G_OBJECT (iter));
516         g_source_remove (timeout);
517
518         /* Perform send */
519         priv->id = MODEST_MAIL_OPERATION_ID_SEND;
520
521         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
522
523         timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
524         modest_tny_send_queue_flush (send_queue);
525         g_source_remove (timeout);
526
527         g_object_unref (G_OBJECT(send_queue));
528         
529         /* Check if the operation was a success */
530         if (!priv->error) {
531                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
532
533                 /* Update the last updated key */
534                 modest_account_mgr_set_int (modest_runtime_get_account_mgr (), 
535                                             tny_account_get_id (TNY_ACCOUNT (info->account)), 
536                                             MODEST_ACCOUNT_LAST_UPDATED, 
537                                             time(NULL), 
538                                             TRUE);
539         }
540
541  out:
542         /* Notify the queue */
543         g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
544
545         /* Frees */
546         g_object_unref (query);
547         g_object_unref (all_folders);
548         g_object_unref (info->mail_op);
549         g_object_unref (info->account);
550         g_object_unref (info->transport_account);
551         g_slice_free (UpdateAccountInfo, info);
552
553         return NULL;
554 }
555
556 gboolean
557 modest_mail_operation_update_account (ModestMailOperation *self,
558                                       const gchar *account_name)
559 {
560         GThread *thread;
561         UpdateAccountInfo *info;
562         ModestMailOperationPrivate *priv;
563         TnyStoreAccount *modest_account;
564         TnyTransportAccount *transport_account;
565         gchar *modest_acc_name;
566
567         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
568         g_return_val_if_fail (account_name, FALSE);
569
570         /* Init mail operation. Set total and done to 0, and do not
571            update them, this way the progress objects will know that
572            we have no clue about the number of the objects */
573         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
574         priv->total = 0;
575         priv->done  = 0;
576         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
577         
578         /* Get the Modest account */
579         modest_account = (TnyStoreAccount *)
580                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
581                                                                      account_name,
582                                                                      TNY_ACCOUNT_TYPE_STORE);
583
584         if (!modest_account) {
585                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
586                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
587                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
588                              "cannot get tny store account for %s\n", account_name);
589                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
590                                                     self);
591                 return FALSE;
592         }
593
594         /* Get the transport account, we can not do it in the thread
595            due to some problems with dbus */
596         modest_acc_name = (gchar *) g_object_get_data (G_OBJECT (modest_account), "modest_account");
597         transport_account = (TnyTransportAccount *)
598                 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
599                                                                                     modest_acc_name);
600         if (!transport_account) {
601                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
602                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
603                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
604                              "cannot get tny transport account for %s\n", modest_acc_name);
605                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
606                                                     self);
607                 return FALSE;
608         }
609
610         /* Create the helper object */
611         info = g_slice_new (UpdateAccountInfo);
612         info->mail_op = g_object_ref (self);
613         info->account = modest_account;
614         info->transport_account = transport_account;
615
616         thread = g_thread_create (update_account_thread, info, FALSE, NULL);
617
618         return TRUE;
619 }
620
621 ModestMailOperationStatus
622 modest_mail_operation_get_status (ModestMailOperation *self)
623 {
624         ModestMailOperationPrivate *priv;
625
626         g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
627         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
628                               MODEST_MAIL_OPERATION_STATUS_INVALID);
629
630         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
631         return priv->status;
632 }
633
634 const GError *
635 modest_mail_operation_get_error (ModestMailOperation *self)
636 {
637         ModestMailOperationPrivate *priv;
638
639         g_return_val_if_fail (self, NULL);
640         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
641
642         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
643         return priv->error;
644 }
645
646 gboolean 
647 modest_mail_operation_cancel (ModestMailOperation *self)
648 {
649         ModestMailOperationPrivate *priv;
650
651         if (!MODEST_IS_MAIL_OPERATION (self)) {
652                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
653                 return FALSE;
654         }
655
656         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
657
658         /* TODO: Tinymail does not support cancel operation  */
659         
660         /* Set new status */
661         priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
662
663         /* Notify the queue */
664         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
665
666         return TRUE;
667 }
668
669 guint 
670 modest_mail_operation_get_task_done (ModestMailOperation *self)
671 {
672         ModestMailOperationPrivate *priv;
673
674         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
675
676         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
677         return priv->done;
678 }
679
680 guint 
681 modest_mail_operation_get_task_total (ModestMailOperation *self)
682 {
683         ModestMailOperationPrivate *priv;
684
685         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
686
687         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
688         return priv->total;
689 }
690
691 gboolean
692 modest_mail_operation_is_finished (ModestMailOperation *self)
693 {
694         ModestMailOperationPrivate *priv;
695         gboolean retval = FALSE;
696
697         if (!MODEST_IS_MAIL_OPERATION (self)) {
698                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
699                 return retval;
700         }
701
702         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
703
704         if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS   ||
705             priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED    ||
706             priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED  ||
707             priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
708                 retval = TRUE;
709         } else {
710                 retval = FALSE;
711         }
712
713         return retval;
714 }
715
716 /* ******************************************************************* */
717 /* ************************** STORE  ACTIONS ************************* */
718 /* ******************************************************************* */
719
720
721 TnyFolder *
722 modest_mail_operation_create_folder (ModestMailOperation *self,
723                                      TnyFolderStore *parent,
724                                      const gchar *name)
725 {
726         ModestTnyFolderRules rules;
727         ModestMailOperationPrivate *priv;
728         TnyFolder *new_folder = NULL;
729         gboolean can_create = FALSE;
730
731         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
732         g_return_val_if_fail (name, NULL);
733         
734         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
735
736         /* Check parent */
737         if (!TNY_IS_FOLDER (parent)) {
738                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
739                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
740                              _("mail_in_ui_folder_create_error"));
741         } else {
742                 /* Check folder rules */
743                 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
744                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
745                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
746                                      MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
747                                      _("mail_in_ui_folder_create_error"));
748                 else
749                         can_create = TRUE;              
750         }
751
752         if (can_create) {
753                 /* Create the folder */
754                 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
755                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
756         }
757
758         /* Notify the queue */
759         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
760
761         return new_folder;
762 }
763
764 void
765 modest_mail_operation_remove_folder (ModestMailOperation *self,
766                                      TnyFolder           *folder,
767                                      gboolean             remove_to_trash)
768 {
769         TnyAccount *account;
770         ModestMailOperationPrivate *priv;
771         ModestTnyFolderRules rules;
772
773         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
774         g_return_if_fail (TNY_IS_FOLDER (folder));
775         
776         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
777         
778         /* Check folder rules */
779         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
780         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
781                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
782                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
783                              _("mail_in_ui_folder_delete_error"));
784                 goto end;
785         }
786
787         /* Get the account */
788         account = tny_folder_get_account (folder);
789
790         /* Delete folder or move to trash */
791         if (remove_to_trash) {
792                 TnyFolder *trash_folder = NULL;
793 /*              TnyFolder *trash_folder, *new_folder; */
794                 trash_folder = modest_tny_account_get_special_folder (account,
795                                                                       TNY_FOLDER_TYPE_TRASH);
796                 /* TODO: error_handling */
797                  modest_mail_operation_xfer_folder (self, folder,
798                                                     TNY_FOLDER_STORE (trash_folder), TRUE);
799 /*              new_folder = modest_mail_operation_xfer_folder (self, folder,  */
800 /*                                                              TNY_FOLDER_STORE (trash_folder), TRUE); */
801 /*              g_object_unref (G_OBJECT (new_folder)); */
802         } else {
803                 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
804
805                 tny_folder_store_remove_folder (parent, folder, &(priv->error));
806                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
807
808                 if (parent)
809                         g_object_unref (G_OBJECT (parent));
810         }
811         g_object_unref (G_OBJECT (account));
812
813  end:
814         /* Notify the queue */
815         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
816 }
817
818 void
819 modest_mail_operation_rename_folder (ModestMailOperation *self,
820                                      TnyFolder *folder,
821                                      const gchar *name)
822 {
823         ModestMailOperationPrivate *priv;
824         ModestTnyFolderRules rules;
825
826         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
827         g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
828         g_return_if_fail (name);
829         
830         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
831
832         /* Check folder rules */
833         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
834         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
835                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
836                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
837                              _("FIXME: unable to rename"));
838         } else {
839                 /* Rename. Camel handles folder subscription/unsubscription */
840                 tny_folder_set_name (folder, name, &(priv->error));
841                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
842         }
843
844         /* Notify the queue */
845         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
846  }
847
848 static void
849 transfer_folder_status_cb (GObject *obj,
850                            TnyStatus *status,  
851                            gpointer user_data)
852 {
853         XFerMsgAsyncHelper *helper = NULL;
854         ModestMailOperation *self;
855         ModestMailOperationPrivate *priv;
856
857         g_return_if_fail (status != NULL);
858         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
859
860         helper = (XFerMsgAsyncHelper *) user_data;
861         g_return_if_fail (helper != NULL);       
862
863         /* Temporary FIX: useful when tinymail send us status
864            information *after* calling the function callback */
865         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
866                 return;
867
868         self = helper->mail_op;
869         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
870
871         if ((status->position == 1) && (status->of_total == 100))
872                 return;
873
874         priv->done = status->position;
875         priv->total = status->of_total;
876
877
878         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
879 }
880
881
882 static void
883 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
884 {
885         XFerFolderAsyncHelper *helper = NULL;
886         ModestMailOperation *self = NULL;
887         ModestMailOperationPrivate *priv = NULL;
888
889         helper = (XFerFolderAsyncHelper *) user_data;
890         self = helper->mail_op;
891
892         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
893
894         if (*err) {
895                 priv->error = g_error_copy (*err);
896                 priv->done = 0;
897                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
898         } else if (cancelled) {
899                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
900                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
901                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
902                              _("Error trying to refresh the contents of %s"),
903                              tny_folder_get_name (folder));
904         } else {
905                 priv->done = 1;
906                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
907         }
908
909         /* Free */
910         g_slice_free   (XFerFolderAsyncHelper, helper);
911         g_object_unref (folder);
912         g_object_unref (into);
913         g_object_unref (new_folder);
914
915         /* Notify the queue */
916         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
917 }
918
919 TnyFolder *
920 modest_mail_operation_xfer_folder (ModestMailOperation *self,
921                                    TnyFolder *folder,
922                                    TnyFolderStore *parent,
923                                    gboolean delete_original)
924 {
925         ModestMailOperationPrivate *priv;
926         TnyFolder *new_folder = NULL;
927         ModestTnyFolderRules rules;
928
929         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
930         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
931         g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
932
933         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
934
935         /* The moveable restriction is applied also to copy operation */
936         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
937         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
938                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
939                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
940                              _("FIXME: unable to rename"));
941         } else {
942                 /* Move/Copy folder */
943                 new_folder = tny_folder_copy (folder,
944                                               parent,
945                                               tny_folder_get_name (folder),
946                                               delete_original,
947                                               &(priv->error));
948         }
949
950         /* Notify the queue */
951         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
952
953         return new_folder;
954 }
955
956 void
957 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
958                                          TnyFolder *folder,
959                                          TnyFolderStore *parent,
960                                          gboolean delete_original)
961 {
962         XFerFolderAsyncHelper *helper = NULL;
963         ModestMailOperationPrivate *priv = NULL;
964         ModestTnyFolderRules rules;
965
966         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
967         g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
968         g_return_if_fail (TNY_IS_FOLDER (folder));
969
970         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
971
972         /* The moveable restriction is applied also to copy operation */
973         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
974         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
975                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
976                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
977                              _("FIXME: unable to rename"));
978         } else {
979                 helper = g_slice_new0 (XFerFolderAsyncHelper);
980                 helper->mail_op = self;
981
982                 /* Move/Copy folder */          
983                 tny_folder_copy_async (folder,
984                                        parent,
985                                        tny_folder_get_name (folder),
986                                        delete_original,
987                                        transfer_folder_cb,
988                                        transfer_folder_status_cb,
989                                        helper);
990         }
991 }
992
993
994 /* ******************************************************************* */
995 /* **************************  MSG  ACTIONS  ************************* */
996 /* ******************************************************************* */
997
998 void          modest_mail_operation_get_msg     (ModestMailOperation *self,
999                                                  TnyHeader *header,
1000                                                  GetMsgAsynUserCallback user_callback,
1001                                                  gpointer user_data)
1002 {
1003         GetMsgAsyncHelper *helper = NULL;
1004         TnyFolder *folder;
1005         ModestMailOperationPrivate *priv;
1006         
1007         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1008         g_return_if_fail (TNY_IS_HEADER (header));
1009         
1010         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1011         folder = tny_header_get_folder (header);
1012
1013         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1014
1015         /* Get message from folder */
1016         if (folder) {
1017                 helper = g_slice_new0 (GetMsgAsyncHelper);
1018                 helper->mail_op = self;
1019                 helper->user_callback = user_callback;
1020                 helper->pending_ops = 1;
1021                 helper->user_data = user_data;
1022
1023                 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1024
1025                 g_object_unref (G_OBJECT (folder));
1026         } else {
1027                 /* Set status failed and set an error */
1028                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1029                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1030                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1031                              _("Error trying to get a message. No folder found for header"));
1032         }
1033 }
1034
1035 static void
1036 get_msg_cb (TnyFolder *folder, 
1037             gboolean cancelled, 
1038             TnyMsg *msg, 
1039             GError **error, 
1040             gpointer user_data)
1041 {
1042         GetMsgAsyncHelper *helper = NULL;
1043         ModestMailOperation *self = NULL;
1044         ModestMailOperationPrivate *priv = NULL;
1045
1046         helper = (GetMsgAsyncHelper *) user_data;
1047         g_return_if_fail (helper != NULL);       
1048         self = helper->mail_op;
1049         g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1050         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1051         
1052         helper->pending_ops--;
1053
1054         /* Check errors and cancel */
1055         if (*error) {
1056                 priv->error = g_error_copy (*error);
1057                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1058                 goto out;
1059         }
1060         if (cancelled) {
1061                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1062                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1063                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1064                              _("Error trying to refresh the contents of %s"),
1065                              tny_folder_get_name (folder));
1066                 goto out;
1067         }
1068
1069         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1070
1071         /* If user defined callback function was defined, call it */
1072         if (helper->user_callback) {
1073                 helper->user_callback (priv->source, msg, helper->user_data);
1074         }
1075
1076         /* Free */
1077  out:
1078         if (helper->pending_ops == 0) {
1079                 g_slice_free (GetMsgAsyncHelper, helper);
1080                 
1081                 /* Notify the queue */
1082                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);  
1083         }
1084 }
1085
1086 static void     
1087 get_msg_status_cb (GObject *obj,
1088                    TnyStatus *status,  
1089                    gpointer user_data)
1090 {
1091         GetMsgAsyncHelper *helper = NULL;
1092         ModestMailOperation *self;
1093         ModestMailOperationPrivate *priv;
1094
1095         g_return_if_fail (status != NULL);
1096         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1097
1098         helper = (GetMsgAsyncHelper *) user_data;
1099         g_return_if_fail (helper != NULL);       
1100
1101         /* Temporary FIX: useful when tinymail send us status
1102            information *after* calling the function callback */
1103         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1104                 return;
1105
1106         self = helper->mail_op;
1107         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1108
1109         if ((status->position == 1) && (status->of_total == 100))
1110                 return;
1111
1112         priv->done = 1;
1113         priv->total = 1;
1114
1115         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1116 }
1117
1118
1119 void          modest_mail_operation_process_msg     (ModestMailOperation *self,
1120                                                      TnyList *header_list, 
1121                                                      GetMsgAsynUserCallback user_callback,
1122                                                      gpointer user_data)
1123 {
1124         ModestMailOperationPrivate *priv = NULL;
1125         GetMsgAsyncHelper *helper = NULL;
1126         TnyHeader *header = NULL;
1127         TnyFolder *folder = NULL;
1128         TnyIterator *iter = NULL;
1129         
1130         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1131         
1132         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1133         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1134
1135         iter = tny_list_create_iterator (header_list); 
1136         priv->done = 1;
1137         priv->total = tny_list_get_length(header_list);
1138
1139         helper = g_slice_new0 (GetMsgAsyncHelper);
1140         helper->mail_op = self;
1141         helper->user_callback = user_callback;
1142         helper->pending_ops = priv->total;
1143         helper->user_data = user_data;
1144
1145         while (!tny_iterator_is_done (iter)) { 
1146                 
1147                 header = TNY_HEADER (tny_iterator_get_current (iter));          
1148                 folder = tny_header_get_folder (header);
1149                                 
1150                 /* Get message from folder */
1151                 if (folder) {
1152                         /* The callback will call it per each header */
1153                         tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1154                         g_object_unref (G_OBJECT (folder));
1155                 } else {                        
1156                         /* Set status failed and set an error */
1157                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1158                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1159                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1160                                      _("Error trying to get a message. No folder found for header"));
1161
1162                         /* Notify the queue */
1163                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1164
1165                         /* free */
1166                         g_slice_free (GetMsgAsyncHelper, helper);
1167                         break;
1168                 }
1169
1170                 g_object_unref (header);                
1171                 tny_iterator_next (iter);
1172         }
1173 }
1174
1175 static void     
1176 update_process_msg_status_cb (GObject *obj,
1177                               TnyStatus *status,  
1178                               gpointer user_data)
1179 {
1180         GetMsgAsyncHelper *helper = NULL;
1181         ModestMailOperation *self;
1182         ModestMailOperationPrivate *priv;
1183
1184         g_return_if_fail (status != NULL);
1185         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1186
1187         helper = (GetMsgAsyncHelper *) user_data;
1188         g_return_if_fail (helper != NULL);       
1189
1190         /* Temporary FIX: useful when tinymail send us status
1191            information *after* calling the function callback */
1192         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1193                 return;
1194
1195         self = helper->mail_op;
1196         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1197
1198         if ((status->position == 1) && (status->of_total == 100))
1199                 return;
1200
1201         if (status->of_total > 0)
1202                 priv->done += status->position/status->of_total;
1203
1204         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1205 }
1206
1207
1208
1209 void 
1210 modest_mail_operation_remove_msg (ModestMailOperation *self,
1211                                   TnyHeader *header,
1212                                   gboolean remove_to_trash)
1213 {
1214         TnyFolder *folder;
1215         ModestMailOperationPrivate *priv;
1216
1217         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1218         g_return_if_fail (TNY_IS_HEADER (header));
1219
1220         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1221         folder = tny_header_get_folder (header);
1222
1223         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1224
1225         /* Delete or move to trash */
1226         if (remove_to_trash) {
1227                 TnyFolder *trash_folder;
1228                 TnyStoreAccount *store_account;
1229
1230                 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1231                 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1232                                                                       TNY_FOLDER_TYPE_TRASH);
1233                 if (trash_folder) {
1234                         TnyList *headers;
1235
1236                         /* Create list */
1237                         headers = tny_simple_list_new ();
1238                         tny_list_append (headers, G_OBJECT (header));
1239                         g_object_unref (header);
1240
1241                         /* Move to trash */
1242                         modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1243                         g_object_unref (headers);
1244 /*                      g_object_unref (trash_folder); */
1245                 } else {
1246                         ModestMailOperationPrivate *priv;
1247
1248                         /* Set status failed and set an error */
1249                         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1250                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1251                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1252                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1253                                      _("Error trying to delete a message. Trash folder not found"));
1254                 }
1255
1256                 g_object_unref (G_OBJECT (store_account));
1257         } else {
1258                 tny_folder_remove_msg (folder, header, &(priv->error));
1259                 if (!priv->error)
1260                         tny_folder_sync(folder, TRUE, &(priv->error));
1261         }
1262
1263         /* Set status */
1264         if (!priv->error)
1265                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1266         else
1267                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1268
1269         /* Free */
1270         g_object_unref (G_OBJECT (folder));
1271
1272         /* Notify the queue */
1273         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1274 }
1275
1276 static void
1277 transfer_msgs_status_cb (GObject *obj,
1278                          TnyStatus *status,  
1279                          gpointer user_data)
1280 {
1281         XFerMsgAsyncHelper *helper = NULL;
1282         ModestMailOperation *self;
1283         ModestMailOperationPrivate *priv;
1284
1285         g_return_if_fail (status != NULL);
1286         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1287
1288         helper = (XFerMsgAsyncHelper *) user_data;
1289         g_return_if_fail (helper != NULL);       
1290
1291         /* Temporary FIX: useful when tinymail send us status
1292            information *after* calling the function callback */
1293         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1294                 return;
1295
1296         self = helper->mail_op;
1297         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1298
1299         if ((status->position == 1) && (status->of_total == 100))
1300                 return;
1301
1302         priv->done = status->position;
1303         priv->total = status->of_total;
1304
1305         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1306 }
1307
1308
1309 static void
1310 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1311 {
1312         XFerMsgAsyncHelper *helper;
1313         ModestMailOperation *self;
1314         ModestMailOperationPrivate *priv;
1315
1316         helper = (XFerMsgAsyncHelper *) user_data;
1317         self = helper->mail_op;
1318
1319         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1320
1321         if (*err) {
1322                 priv->error = g_error_copy (*err);
1323                 priv->done = 0;
1324                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
1325         } else if (cancelled) {
1326                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1327                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1328                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1329                              _("Error trying to refresh the contents of %s"),
1330                              tny_folder_get_name (folder));
1331         } else {
1332                 priv->done = 1;
1333                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1334         }
1335
1336         /* Free */
1337 /*      g_object_unref (helper->headers); */
1338 /*      g_object_unref (helper->dest_folder); */
1339 /*      g_object_unref (helper->mail_op); */
1340         g_slice_free   (XFerMsgAsyncHelper, helper);
1341         g_object_unref (folder);
1342
1343         /* Notify the queue */
1344         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1345 }
1346
1347 void
1348 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1349                                  TnyList *headers, 
1350                                  TnyFolder *folder, 
1351                                  gboolean delete_original)
1352 {
1353         ModestMailOperationPrivate *priv;
1354         TnyIterator *iter;
1355         TnyFolder *src_folder;
1356         XFerMsgAsyncHelper *helper;
1357         TnyHeader *header;
1358
1359         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1360         g_return_if_fail (TNY_IS_LIST (headers));
1361         g_return_if_fail (TNY_IS_FOLDER (folder));
1362
1363         /* Pick references for async calls */
1364         g_object_ref (folder);
1365
1366         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1367         priv->total = 1;
1368         priv->done = 0;
1369         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1370
1371         /* Create the helper */
1372         helper = g_slice_new0 (XFerMsgAsyncHelper);
1373         helper->mail_op = self;
1374         helper->dest_folder = g_object_ref(folder);
1375         helper->headers = g_object_ref(headers);
1376
1377         /* Get source folder */
1378         iter = tny_list_create_iterator (headers);
1379         header = TNY_HEADER (tny_iterator_get_current (iter));
1380         src_folder = tny_header_get_folder (header);
1381         g_object_unref (header);
1382         g_object_unref (iter);
1383
1384         /* Transfer messages */
1385         tny_folder_transfer_msgs_async (src_folder, 
1386                                         headers, 
1387                                         folder, 
1388                                         delete_original, 
1389                                         transfer_msgs_cb, 
1390                                         transfer_msgs_status_cb,
1391                                         helper);
1392 }
1393
1394
1395 static void
1396 on_refresh_folder (TnyFolder   *folder, 
1397                    gboolean     cancelled, 
1398                    GError     **error,
1399                    gpointer     user_data)
1400 {
1401         ModestMailOperation *self;
1402         ModestMailOperationPrivate *priv;
1403
1404         self = MODEST_MAIL_OPERATION (user_data);
1405         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1406
1407         if (*error) {
1408                 priv->error = g_error_copy (*error);
1409                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1410                 goto out;
1411         }
1412
1413         if (cancelled) {
1414                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1415                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1416                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1417                              _("Error trying to refresh the contents of %s"),
1418                              tny_folder_get_name (folder));
1419                 goto out;
1420         }
1421
1422         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1423
1424  out:
1425         /* Free */
1426         g_object_unref (folder);
1427
1428         /* Notify the queue */
1429         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1430 }
1431
1432 static void
1433 on_refresh_folder_status_update (GObject *obj,
1434                                  TnyStatus *status,
1435                                  gpointer user_data)
1436 {
1437         ModestMailOperation *self;
1438         ModestMailOperationPrivate *priv;
1439
1440         g_return_if_fail (status != NULL);
1441         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1442
1443         /* Temporary FIX: useful when tinymail send us status
1444            information *after* calling the function callback */
1445         if (!MODEST_IS_MAIL_OPERATION (user_data))
1446                 return;
1447
1448         self = MODEST_MAIL_OPERATION (user_data);
1449         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1450
1451         priv->done = status->position;
1452         priv->total = status->of_total;
1453
1454         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1455 }
1456
1457 void 
1458 modest_mail_operation_refresh_folder  (ModestMailOperation *self,
1459                                        TnyFolder *folder)
1460 {
1461         ModestMailOperationPrivate *priv;
1462
1463         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1464
1465         /* Pick a reference */
1466         g_object_ref (folder);
1467
1468         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1469
1470         /* Refresh the folder. TODO: tinymail could issue a status
1471            updates before the callback call then this could happen. We
1472            must review the design */
1473         tny_folder_refresh_async (folder,
1474                                   on_refresh_folder,
1475                                   on_refresh_folder_status_update,
1476                                   self);
1477 }
1478
1479 void
1480 _modest_mail_operation_notify_end (ModestMailOperation *self)
1481 {
1482         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1483 }