Build fix, updating API changes from Tinymail
[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         XferMsgsAsynUserCallback user_callback; 
120         gpointer user_data;
121 } XFerMsgAsyncHelper;
122
123 typedef struct _XFerFolderAsyncHelper
124 {
125         ModestMailOperation *mail_op;
126
127 } XFerFolderAsyncHelper;
128
129
130 /* globals */
131 static GObjectClass *parent_class = NULL;
132
133 static guint signals[NUM_SIGNALS] = {0};
134
135 GType
136 modest_mail_operation_get_type (void)
137 {
138         static GType my_type = 0;
139         if (!my_type) {
140                 static const GTypeInfo my_info = {
141                         sizeof(ModestMailOperationClass),
142                         NULL,           /* base init */
143                         NULL,           /* base finalize */
144                         (GClassInitFunc) modest_mail_operation_class_init,
145                         NULL,           /* class finalize */
146                         NULL,           /* class data */
147                         sizeof(ModestMailOperation),
148                         1,              /* n_preallocs */
149                         (GInstanceInitFunc) modest_mail_operation_init,
150                         NULL
151                 };
152                 my_type = g_type_register_static (G_TYPE_OBJECT,
153                                                   "ModestMailOperation",
154                                                   &my_info, 0);
155         }
156         return my_type;
157 }
158
159 static void
160 modest_mail_operation_class_init (ModestMailOperationClass *klass)
161 {
162         GObjectClass *gobject_class;
163         gobject_class = (GObjectClass*) klass;
164
165         parent_class            = g_type_class_peek_parent (klass);
166         gobject_class->finalize = modest_mail_operation_finalize;
167
168         g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
169
170         /**
171          * ModestMailOperation::progress-changed
172          * @self: the #MailOperation that emits the signal
173          * @user_data: user data set when the signal handler was connected
174          *
175          * Emitted when the progress of a mail operation changes
176          */
177         signals[PROGRESS_CHANGED_SIGNAL] = 
178                 g_signal_new ("progress-changed",
179                               G_TYPE_FROM_CLASS (gobject_class),
180                               G_SIGNAL_RUN_FIRST,
181                               G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
182                               NULL, NULL,
183                               g_cclosure_marshal_VOID__VOID,
184                               G_TYPE_NONE, 0);
185 }
186
187 static void
188 modest_mail_operation_init (ModestMailOperation *obj)
189 {
190         ModestMailOperationPrivate *priv;
191
192         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
193
194         priv->status   = MODEST_MAIL_OPERATION_STATUS_INVALID;
195         priv->id       = MODEST_MAIL_OPERATION_ID_UNKNOWN;
196         priv->error    = NULL;
197         priv->done     = 0;
198         priv->total    = 0;
199         priv->source = NULL;
200 }
201
202 static void
203 modest_mail_operation_finalize (GObject *obj)
204 {
205         ModestMailOperationPrivate *priv;
206
207         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
208
209         if (priv->error) {
210                 g_error_free (priv->error);
211                 priv->error = NULL;
212         }
213         if (priv->source) {
214                 g_object_unref (priv->source);
215                 priv->source = NULL;
216         }
217
218         G_OBJECT_CLASS(parent_class)->finalize (obj);
219 }
220
221 ModestMailOperation*
222 modest_mail_operation_new (ModestMailOperationId id, 
223                            GObject *source)
224 {
225         ModestMailOperation *obj;
226         ModestMailOperationPrivate *priv;
227                 
228         obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
229         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
230
231         priv->id = id;
232         if (source != NULL)
233                 priv->source = g_object_ref(source);
234
235         return obj;
236 }
237
238
239 ModestMailOperationId
240 modest_mail_operation_get_id (ModestMailOperation *self)
241 {
242         ModestMailOperationPrivate *priv;
243
244         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
245         
246         return priv->id;
247 }
248
249 gboolean 
250 modest_mail_operation_is_mine (ModestMailOperation *self, 
251                                GObject *me)
252 {
253         ModestMailOperationPrivate *priv;
254
255         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
256         if (priv->source == NULL) return FALSE;
257
258         return priv->source == me;
259 }
260
261
262 void
263 modest_mail_operation_send_mail (ModestMailOperation *self,
264                                  TnyTransportAccount *transport_account,
265                                  TnyMsg* msg)
266 {
267         TnySendQueue *send_queue;
268         
269         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
270         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
271         g_return_if_fail (TNY_IS_MSG (msg));
272         
273         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
274         if (!TNY_IS_SEND_QUEUE(send_queue))
275                 g_printerr ("modest: could not find send queue for account\n");
276         else {
277                 GError *err = NULL;
278                 tny_send_queue_add (send_queue, msg, &err);
279                 if (err) {
280                         g_printerr ("modest: error adding msg to send queue: %s\n",
281                                     err->message);
282                         g_error_free (err);
283                 } else {
284                         /* g_message ("modest: message added to send queue"); */
285                 }
286         }
287
288         /* Notify the queue */
289         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
290 }
291
292 void
293 modest_mail_operation_send_new_mail (ModestMailOperation *self,
294                                      TnyTransportAccount *transport_account,
295                                      const gchar *from,  const gchar *to,
296                                      const gchar *cc,  const gchar *bcc,
297                                      const gchar *subject, const gchar *plain_body,
298                                      const gchar *html_body,
299                                      const GList *attachments_list,
300                                      TnyHeaderFlags priority_flags)
301 {
302         TnyMsg *new_msg;
303         ModestMailOperationPrivate *priv = NULL;
304         /* GList *node = NULL; */
305
306         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
307         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
308
309         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
310
311         /* Check parametters */
312         if (to == NULL) {
313                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
314                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
315                              _("Error trying to send a mail. You need to set at least one recipient"));
316                 return;
317         }
318
319         if (html_body == NULL) {
320                 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
321         } else {
322                 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
323         }
324         if (!new_msg) {
325                 g_printerr ("modest: failed to create a new msg\n");
326                 return;
327         }
328
329         /* TODO: add priority handling. It's received in the priority_flags operator, and
330            it should have effect in the sending operation */
331
332         /* Call mail operation */
333         modest_mail_operation_send_mail (self, transport_account, new_msg);
334
335         /* Free */
336         g_object_unref (G_OBJECT (new_msg));
337 }
338
339 void
340 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
341                                       TnyTransportAccount *transport_account,
342                                       const gchar *from,  const gchar *to,
343                                       const gchar *cc,  const gchar *bcc,
344                                       const gchar *subject, const gchar *plain_body,
345                                       const gchar *html_body,
346                                       const GList *attachments_list,
347                                       TnyHeaderFlags priority_flags)
348 {
349         TnyMsg *msg = NULL;
350         TnyFolder *folder = NULL;
351         ModestMailOperationPrivate *priv = NULL;
352         GError *err = NULL;
353
354         /* GList *node = NULL; */
355
356         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
357         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
358
359         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
360
361         if (html_body == NULL) {
362                 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
363         } else {
364                 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
365         }
366         if (!msg) {
367                 g_printerr ("modest: failed to create a new msg\n");
368                 goto cleanup;
369         }
370
371         folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
372         if (!folder) {
373                 g_printerr ("modest: failed to find Drafts folder\n");
374                 goto cleanup;
375         }
376         
377         tny_folder_add_msg (folder, msg, &err);
378         if (err) {
379                 g_printerr ("modest: error adding msg to Drafts folder: %s",
380                             err->message);
381                 g_error_free (err);
382                 goto cleanup;
383         }
384
385         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
386
387         /* Free */
388 cleanup:
389         if (msg)
390                 g_object_unref (G_OBJECT(msg));
391         if (folder)
392                 g_object_unref (G_OBJECT(folder));
393 }
394
395 typedef struct 
396 {
397         ModestMailOperation *mail_op;
398         TnyStoreAccount *account;
399         TnyTransportAccount *transport_account;
400 } UpdateAccountInfo;
401
402 static void
403 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
404 {
405         TnyIterator *iter;
406         TnyList *folders = tny_simple_list_new ();
407
408         tny_folder_store_get_folders (store, folders, query, NULL);
409         iter = tny_list_create_iterator (folders);
410
411         while (!tny_iterator_is_done (iter)) {
412
413                 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
414
415                 tny_list_prepend (all_folders, G_OBJECT (folder));
416                 recurse_folders (folder, query, all_folders);    
417                 g_object_unref (G_OBJECT (folder));
418
419                 tny_iterator_next (iter);
420         }
421          g_object_unref (G_OBJECT (iter));
422          g_object_unref (G_OBJECT (folders));
423 }
424
425 /* 
426  * Used by update_account_thread to emit the signal from the main
427  * loop. We call it inside an idle call to achieve that 
428  */
429 static gboolean
430 notify_update_account_observers (gpointer data)
431 {
432         ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
433
434         g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
435
436         return TRUE;
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         ModestTnySendQueue *send_queue;
464         gint timeout;
465
466         info = (UpdateAccountInfo *) thr_user_data;
467         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
468
469         /* Get all the folders We can do it synchronously because
470            we're already running in a different thread than the UI */
471         all_folders = tny_simple_list_new ();
472         query = tny_folder_store_query_new ();
473         tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
474         tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
475                                       all_folders,
476                                       query,
477                                       &(priv->error));
478         if (priv->error) {
479                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
480                 goto out;
481         }
482
483         iter = tny_list_create_iterator (all_folders);
484         while (!tny_iterator_is_done (iter)) {
485                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
486
487                 recurse_folders (folder, query, all_folders);
488                 tny_iterator_next (iter);
489         }
490         g_object_unref (G_OBJECT (iter));
491
492         /* Update status and notify. We need to call the notification
493            with a source functopm in order to call it from the main
494            loop. We need that in order not to get into trouble with
495            Gtk+. We use a timeout in order to provide more status
496            information, because the sync tinymail call does not
497            provide it for the moment */
498         timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
499
500         /* Refresh folders */
501         iter = tny_list_create_iterator (all_folders);
502         while (!tny_iterator_is_done (iter) && !priv->error) {
503
504                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
505
506                 /* Refresh the folder */
507                 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
508
509                 if (priv->error) {
510                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
511                 }
512
513                 g_object_unref (G_OBJECT (folder));
514                 tny_iterator_next (iter);
515         }
516         g_object_unref (G_OBJECT (iter));
517         g_source_remove (timeout);
518
519         /* Perform send */
520         priv->id = MODEST_MAIL_OPERATION_ID_SEND;
521
522         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
523
524         timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
525         modest_tny_send_queue_flush (send_queue);
526         g_source_remove (timeout);
527
528         g_object_unref (G_OBJECT(send_queue));
529         
530         /* Check if the operation was a success */
531         if (!priv->error) {
532                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
533
534                 /* Update the last updated key */
535                 modest_account_mgr_set_int (modest_runtime_get_account_mgr (), 
536                                             tny_account_get_id (TNY_ACCOUNT (info->account)), 
537                                             MODEST_ACCOUNT_LAST_UPDATED, 
538                                             time(NULL), 
539                                             TRUE);
540         }
541
542  out:
543         /* Notify the queue */
544         g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
545
546         /* Frees */
547         g_object_unref (query);
548         g_object_unref (all_folders);
549         g_object_unref (info->mail_op);
550         g_object_unref (info->account);
551         g_object_unref (info->transport_account);
552         g_slice_free (UpdateAccountInfo, info);
553
554         return NULL;
555 }
556
557 gboolean
558 modest_mail_operation_update_account (ModestMailOperation *self,
559                                       const gchar *account_name)
560 {
561         GThread *thread;
562         UpdateAccountInfo *info;
563         ModestMailOperationPrivate *priv;
564         TnyStoreAccount *modest_account;
565         TnyTransportAccount *transport_account;
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         transport_account = (TnyTransportAccount *)
597                 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
598                                                                                     account_name);
599         if (!transport_account) {
600                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
601                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
602                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
603                              "cannot get tny transport account for %s\n", account_name);
604                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), 
605                                                     self);
606                 return FALSE;
607         }
608
609         /* Create the helper object */
610         info = g_slice_new (UpdateAccountInfo);
611         info->mail_op = g_object_ref (self);
612         info->account = modest_account;
613         info->transport_account = transport_account;
614
615         thread = g_thread_create (update_account_thread, info, FALSE, NULL);
616
617         return TRUE;
618 }
619
620 ModestMailOperationStatus
621 modest_mail_operation_get_status (ModestMailOperation *self)
622 {
623         ModestMailOperationPrivate *priv;
624
625         g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
626         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
627                               MODEST_MAIL_OPERATION_STATUS_INVALID);
628
629         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
630         return priv->status;
631 }
632
633 const GError *
634 modest_mail_operation_get_error (ModestMailOperation *self)
635 {
636         ModestMailOperationPrivate *priv;
637
638         g_return_val_if_fail (self, NULL);
639         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
640
641         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
642         return priv->error;
643 }
644
645 gboolean 
646 modest_mail_operation_cancel (ModestMailOperation *self)
647 {
648         ModestMailOperationPrivate *priv;
649
650         if (!MODEST_IS_MAIL_OPERATION (self)) {
651                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
652                 return FALSE;
653         }
654
655         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
656
657         /* TODO: Tinymail does not support cancel operation  */
658         
659         /* Set new status */
660         priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
661
662         /* Notify the queue */
663         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
664
665         return TRUE;
666 }
667
668 guint 
669 modest_mail_operation_get_task_done (ModestMailOperation *self)
670 {
671         ModestMailOperationPrivate *priv;
672
673         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
674
675         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
676         return priv->done;
677 }
678
679 guint 
680 modest_mail_operation_get_task_total (ModestMailOperation *self)
681 {
682         ModestMailOperationPrivate *priv;
683
684         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
685
686         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
687         return priv->total;
688 }
689
690 gboolean
691 modest_mail_operation_is_finished (ModestMailOperation *self)
692 {
693         ModestMailOperationPrivate *priv;
694         gboolean retval = FALSE;
695
696         if (!MODEST_IS_MAIL_OPERATION (self)) {
697                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
698                 return retval;
699         }
700
701         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
702
703         if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS   ||
704             priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED    ||
705             priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED  ||
706             priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
707                 retval = TRUE;
708         } else {
709                 retval = FALSE;
710         }
711
712         return retval;
713 }
714
715 /* ******************************************************************* */
716 /* ************************** STORE  ACTIONS ************************* */
717 /* ******************************************************************* */
718
719
720 TnyFolder *
721 modest_mail_operation_create_folder (ModestMailOperation *self,
722                                      TnyFolderStore *parent,
723                                      const gchar *name)
724 {
725         ModestTnyFolderRules rules;
726         ModestMailOperationPrivate *priv;
727         TnyFolder *new_folder = NULL;
728         gboolean can_create = FALSE;
729
730         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
731         g_return_val_if_fail (name, NULL);
732         
733         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
734
735         /* Check parent */
736         if (!TNY_IS_FOLDER (parent)) {
737                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
738                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
739                              _("mail_in_ui_folder_create_error"));
740         } else {
741                 /* Check folder rules */
742                 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
743                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
744                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
745                                      MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
746                                      _("mail_in_ui_folder_create_error"));
747                 else
748                         can_create = TRUE;              
749         }
750
751         if (can_create) {
752                 /* Create the folder */
753                 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
754                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
755         }
756
757         /* Notify the queue */
758         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
759
760         return new_folder;
761 }
762
763 void
764 modest_mail_operation_remove_folder (ModestMailOperation *self,
765                                      TnyFolder           *folder,
766                                      gboolean             remove_to_trash)
767 {
768         TnyAccount *account;
769         ModestMailOperationPrivate *priv;
770         ModestTnyFolderRules rules;
771
772         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
773         g_return_if_fail (TNY_IS_FOLDER (folder));
774         
775         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
776         
777         /* Check folder rules */
778         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
779         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
780                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
781                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
782                              _("mail_in_ui_folder_delete_error"));
783                 goto end;
784         }
785
786         /* Get the account */
787         account = tny_folder_get_account (folder);
788
789         /* Delete folder or move to trash */
790         if (remove_to_trash) {
791                 TnyFolder *trash_folder = NULL;
792 /*              TnyFolder *trash_folder, *new_folder; */
793                 trash_folder = modest_tny_account_get_special_folder (account,
794                                                                       TNY_FOLDER_TYPE_TRASH);
795                 /* TODO: error_handling */
796                  modest_mail_operation_xfer_folder (self, folder,
797                                                     TNY_FOLDER_STORE (trash_folder), TRUE);
798 /*              new_folder = modest_mail_operation_xfer_folder (self, folder,  */
799 /*                                                              TNY_FOLDER_STORE (trash_folder), TRUE); */
800 /*              g_object_unref (G_OBJECT (new_folder)); */
801         } else {
802                 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
803
804                 tny_folder_store_remove_folder (parent, folder, &(priv->error));
805                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
806
807                 if (parent)
808                         g_object_unref (G_OBJECT (parent));
809         }
810         g_object_unref (G_OBJECT (account));
811
812  end:
813         /* Notify the queue */
814         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
815 }
816
817 void
818 modest_mail_operation_rename_folder (ModestMailOperation *self,
819                                      TnyFolder *folder,
820                                      const gchar *name)
821 {
822         ModestMailOperationPrivate *priv;
823         ModestTnyFolderRules rules;
824
825         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
826         g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
827         g_return_if_fail (name);
828         
829         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
830
831         /* Check folder rules */
832         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
833         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
834                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
835                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
836                              _("FIXME: unable to rename"));
837         } else {
838                 /* Rename. Camel handles folder subscription/unsubscription */
839
840                 TnyFolderStore *into;
841                 TnyFolder *nfol;
842
843                 into = tny_folder_get_folder_store (folder);
844                 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
845                 if (into)
846                         g_object_unref (into);
847                 if (nfol)
848                         g_object_unref (nfol);
849
850                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
851         }
852
853         /* Notify the queue */
854         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
855  }
856
857 static void
858 transfer_folder_status_cb (GObject *obj,
859                            TnyStatus *status,  
860                            gpointer user_data)
861 {
862         XFerMsgAsyncHelper *helper = NULL;
863         ModestMailOperation *self;
864         ModestMailOperationPrivate *priv;
865
866         g_return_if_fail (status != NULL);
867         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
868
869         helper = (XFerMsgAsyncHelper *) user_data;
870         g_return_if_fail (helper != NULL);       
871
872         /* Temporary FIX: useful when tinymail send us status
873            information *after* calling the function callback */
874         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
875                 return;
876
877         self = helper->mail_op;
878         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
879
880         if ((status->position == 1) && (status->of_total == 100))
881                 return;
882
883         priv->done = status->position;
884         priv->total = status->of_total;
885
886
887         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
888 }
889
890
891 static void
892 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
893 {
894         XFerFolderAsyncHelper *helper = NULL;
895         ModestMailOperation *self = NULL;
896         ModestMailOperationPrivate *priv = NULL;
897
898         helper = (XFerFolderAsyncHelper *) user_data;
899         self = helper->mail_op;
900
901         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
902
903         if (*err) {
904                 priv->error = g_error_copy (*err);
905                 priv->done = 0;
906                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
907         } else if (cancelled) {
908                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
909                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
910                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
911                              _("Error trying to refresh the contents of %s"),
912                              tny_folder_get_name (folder));
913         } else {
914                 priv->done = 1;
915                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
916         }
917
918         /* Free */
919         g_slice_free   (XFerFolderAsyncHelper, helper);
920         g_object_unref (folder);
921         g_object_unref (into);
922         g_object_unref (new_folder);
923
924         /* Notify the queue */
925         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
926 }
927
928 TnyFolder *
929 modest_mail_operation_xfer_folder (ModestMailOperation *self,
930                                    TnyFolder *folder,
931                                    TnyFolderStore *parent,
932                                    gboolean delete_original)
933 {
934         ModestMailOperationPrivate *priv;
935         TnyFolder *new_folder = NULL;
936         ModestTnyFolderRules rules;
937
938         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
939         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
940         g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
941
942         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
943
944         /* The moveable restriction is applied also to copy operation */
945         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
946         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
947                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
948                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
949                              _("FIXME: unable to rename"));
950         } else {
951                 /* Move/Copy folder */
952                 new_folder = tny_folder_copy (folder,
953                                               parent,
954                                               tny_folder_get_name (folder),
955                                               delete_original,
956                                               &(priv->error));
957         }
958
959         /* Notify the queue */
960         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
961
962         return new_folder;
963 }
964
965 void
966 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
967                                          TnyFolder *folder,
968                                          TnyFolderStore *parent,
969                                          gboolean delete_original)
970 {
971         XFerFolderAsyncHelper *helper = NULL;
972         ModestMailOperationPrivate *priv = NULL;
973         ModestTnyFolderRules rules;
974
975         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
976         g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
977         g_return_if_fail (TNY_IS_FOLDER (folder));
978
979         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
980
981         /* Pick references for async calls */
982         g_object_ref (folder);
983         g_object_ref (parent);
984
985         /* The moveable restriction is applied also to copy operation */
986         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
987         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
988                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
989                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
990                              _("FIXME: unable to rename"));
991         } else {
992                 helper = g_slice_new0 (XFerFolderAsyncHelper);
993                 helper->mail_op = self;
994
995                 /* Move/Copy folder */          
996                 tny_folder_copy_async (folder,
997                                        parent,
998                                        tny_folder_get_name (folder),
999                                        delete_original,
1000                                        transfer_folder_cb,
1001                                        transfer_folder_status_cb,
1002                                        helper);
1003         }
1004 }
1005
1006
1007 /* ******************************************************************* */
1008 /* **************************  MSG  ACTIONS  ************************* */
1009 /* ******************************************************************* */
1010
1011 void          modest_mail_operation_get_msg     (ModestMailOperation *self,
1012                                                  TnyHeader *header,
1013                                                  GetMsgAsynUserCallback user_callback,
1014                                                  gpointer user_data)
1015 {
1016         GetMsgAsyncHelper *helper = NULL;
1017         TnyFolder *folder;
1018         ModestMailOperationPrivate *priv;
1019         
1020         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1021         g_return_if_fail (TNY_IS_HEADER (header));
1022         
1023         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1024         folder = tny_header_get_folder (header);
1025
1026         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1027
1028         /* Get message from folder */
1029         if (folder) {
1030                 helper = g_slice_new0 (GetMsgAsyncHelper);
1031                 helper->mail_op = self;
1032                 helper->user_callback = user_callback;
1033                 helper->pending_ops = 1;
1034                 helper->user_data = user_data;
1035
1036                 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1037
1038                 g_object_unref (G_OBJECT (folder));
1039         } else {
1040                 /* Set status failed and set an error */
1041                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1042                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1043                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1044                              _("Error trying to get a message. No folder found for header"));
1045         }
1046 }
1047
1048 static void
1049 get_msg_cb (TnyFolder *folder, 
1050             gboolean cancelled, 
1051             TnyMsg *msg, 
1052             GError **error, 
1053             gpointer user_data)
1054 {
1055         GetMsgAsyncHelper *helper = NULL;
1056         ModestMailOperation *self = NULL;
1057         ModestMailOperationPrivate *priv = NULL;
1058
1059         helper = (GetMsgAsyncHelper *) user_data;
1060         g_return_if_fail (helper != NULL);       
1061         self = helper->mail_op;
1062         g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1063         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1064         
1065         helper->pending_ops--;
1066
1067         /* Check errors and cancel */
1068         if (*error) {
1069                 priv->error = g_error_copy (*error);
1070                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1071                 goto out;
1072         }
1073         if (cancelled) {
1074                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1075                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1076                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1077                              _("Error trying to refresh the contents of %s"),
1078                              tny_folder_get_name (folder));
1079                 goto out;
1080         }
1081
1082         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1083
1084         /* If user defined callback function was defined, call it */
1085         if (helper->user_callback) {
1086                 helper->user_callback (priv->source, msg, helper->user_data);
1087         }
1088
1089         /* Free */
1090  out:
1091         if (helper->pending_ops == 0) {
1092                 g_slice_free (GetMsgAsyncHelper, helper);
1093                 
1094                 /* Notify the queue */
1095                 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);  
1096         }
1097 }
1098
1099 static void     
1100 get_msg_status_cb (GObject *obj,
1101                    TnyStatus *status,  
1102                    gpointer user_data)
1103 {
1104         GetMsgAsyncHelper *helper = NULL;
1105         ModestMailOperation *self;
1106         ModestMailOperationPrivate *priv;
1107
1108         g_return_if_fail (status != NULL);
1109         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1110
1111         helper = (GetMsgAsyncHelper *) user_data;
1112         g_return_if_fail (helper != NULL);       
1113
1114         /* Temporary FIX: useful when tinymail send us status
1115            information *after* calling the function callback */
1116         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1117                 return;
1118
1119         self = helper->mail_op;
1120         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1121
1122         if ((status->position == 1) && (status->of_total == 100))
1123                 return;
1124
1125         priv->done = 1;
1126         priv->total = 1;
1127
1128         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1129 }
1130
1131
1132 void          modest_mail_operation_process_msg     (ModestMailOperation *self,
1133                                                      TnyList *header_list, 
1134                                                      GetMsgAsynUserCallback user_callback,
1135                                                      gpointer user_data)
1136 {
1137         ModestMailOperationPrivate *priv = NULL;
1138         GetMsgAsyncHelper *helper = NULL;
1139         TnyHeader *header = NULL;
1140         TnyFolder *folder = NULL;
1141         TnyIterator *iter = NULL;
1142         
1143         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1144         
1145         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1146         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1147
1148         iter = tny_list_create_iterator (header_list); 
1149         priv->done = 1;
1150         priv->total = tny_list_get_length(header_list);
1151
1152         helper = g_slice_new0 (GetMsgAsyncHelper);
1153         helper->mail_op = self;
1154         helper->user_callback = user_callback;
1155         helper->pending_ops = priv->total;
1156         helper->user_data = user_data;
1157
1158         while (!tny_iterator_is_done (iter)) { 
1159                 
1160                 header = TNY_HEADER (tny_iterator_get_current (iter));          
1161                 folder = tny_header_get_folder (header);
1162                                 
1163                 /* Get message from folder */
1164                 if (folder) {
1165                         /* The callback will call it per each header */
1166                         tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1167                         g_object_unref (G_OBJECT (folder));
1168                 } else {                        
1169                         /* Set status failed and set an error */
1170                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1171                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1172                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1173                                      _("Error trying to get a message. No folder found for header"));
1174
1175                         /* Notify the queue */
1176                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1177
1178                         /* free */
1179                         g_slice_free (GetMsgAsyncHelper, helper);
1180                         break;
1181                 }
1182
1183                 g_object_unref (header);                
1184                 tny_iterator_next (iter);
1185         }
1186 }
1187
1188 static void     
1189 update_process_msg_status_cb (GObject *obj,
1190                               TnyStatus *status,  
1191                               gpointer user_data)
1192 {
1193         GetMsgAsyncHelper *helper = NULL;
1194         ModestMailOperation *self;
1195         ModestMailOperationPrivate *priv;
1196
1197         g_return_if_fail (status != NULL);
1198         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1199
1200         helper = (GetMsgAsyncHelper *) user_data;
1201         g_return_if_fail (helper != NULL);       
1202
1203         /* Temporary FIX: useful when tinymail send us status
1204            information *after* calling the function callback */
1205         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1206                 return;
1207
1208         self = helper->mail_op;
1209         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1210
1211         if ((status->position == 1) && (status->of_total == 100))
1212                 return;
1213
1214         if (status->of_total > 0)
1215                 priv->done += status->position/status->of_total;
1216
1217         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1218 }
1219
1220
1221
1222 void 
1223 modest_mail_operation_remove_msg (ModestMailOperation *self,
1224                                   TnyHeader *header,
1225                                   gboolean remove_to_trash)
1226 {
1227         TnyFolder *folder;
1228         ModestMailOperationPrivate *priv;
1229
1230         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1231         g_return_if_fail (TNY_IS_HEADER (header));
1232
1233         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1234         folder = tny_header_get_folder (header);
1235
1236         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1237
1238         /* Delete or move to trash */
1239         if (remove_to_trash) {
1240                 TnyFolder *trash_folder;
1241                 TnyStoreAccount *store_account;
1242
1243                 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1244                 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1245                                                                       TNY_FOLDER_TYPE_TRASH);
1246                 if (trash_folder) {
1247                         TnyList *headers;
1248
1249                         /* Create list */
1250                         headers = tny_simple_list_new ();
1251                         tny_list_append (headers, G_OBJECT (header));
1252                         g_object_unref (header);
1253
1254                         /* Move to trash */
1255                         modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1256                         g_object_unref (headers);
1257 /*                      g_object_unref (trash_folder); */
1258                 } else {
1259                         ModestMailOperationPrivate *priv;
1260
1261                         /* Set status failed and set an error */
1262                         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1263                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1264                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1265                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1266                                      _("Error trying to delete a message. Trash folder not found"));
1267                 }
1268
1269                 g_object_unref (G_OBJECT (store_account));
1270         } else {
1271                 tny_folder_remove_msg (folder, header, &(priv->error));
1272                 if (!priv->error)
1273                         tny_folder_sync(folder, TRUE, &(priv->error));
1274         }
1275
1276         /* Set status */
1277         if (!priv->error)
1278                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1279         else
1280                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1281
1282         /* Free */
1283         g_object_unref (G_OBJECT (folder));
1284
1285         /* Notify the queue */
1286         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1287 }
1288
1289 static void
1290 transfer_msgs_status_cb (GObject *obj,
1291                          TnyStatus *status,  
1292                          gpointer user_data)
1293 {
1294         XFerMsgAsyncHelper *helper = NULL;
1295         ModestMailOperation *self;
1296         ModestMailOperationPrivate *priv;
1297
1298         g_return_if_fail (status != NULL);
1299         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1300
1301         helper = (XFerMsgAsyncHelper *) user_data;
1302         g_return_if_fail (helper != NULL);       
1303
1304         /* Temporary FIX: useful when tinymail send us status
1305            information *after* calling the function callback */
1306         if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1307                 return;
1308
1309         self = helper->mail_op;
1310         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1311
1312         if ((status->position == 1) && (status->of_total == 100))
1313                 return;
1314
1315         priv->done = status->position;
1316         priv->total = status->of_total;
1317
1318         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1319 }
1320
1321
1322 static void
1323 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1324 {
1325         XFerMsgAsyncHelper *helper;
1326         ModestMailOperation *self;
1327         ModestMailOperationPrivate *priv;
1328
1329         helper = (XFerMsgAsyncHelper *) user_data;
1330         self = helper->mail_op;
1331
1332         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1333
1334         if (*err) {
1335                 priv->error = g_error_copy (*err);
1336                 priv->done = 0;
1337                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;     
1338         } else if (cancelled) {
1339                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1340                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1341                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1342                              _("Error trying to refresh the contents of %s"),
1343                              tny_folder_get_name (folder));
1344         } else {
1345                 priv->done = 1;
1346                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1347         }
1348
1349         /* If user defined callback function was defined, call it */
1350         if (helper->user_callback) {
1351                 helper->user_callback (priv->source, helper->user_data);
1352         }
1353
1354         /* Free */
1355         g_object_unref (helper->headers);
1356         g_object_unref (helper->dest_folder);
1357         g_object_unref (helper->mail_op);
1358         g_slice_free   (XFerMsgAsyncHelper, helper);
1359         g_object_unref (folder);
1360
1361         /* Notify the queue */
1362         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1363 }
1364
1365 void
1366 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1367                                  TnyList *headers, 
1368                                  TnyFolder *folder, 
1369                                  gboolean delete_original,
1370                                  XferMsgsAsynUserCallback user_callback,
1371                                  gpointer user_data)
1372 {
1373         ModestMailOperationPrivate *priv;
1374         TnyIterator *iter;
1375         TnyFolder *src_folder;
1376         XFerMsgAsyncHelper *helper;
1377         TnyHeader *header;
1378
1379         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1380         g_return_if_fail (TNY_IS_LIST (headers));
1381         g_return_if_fail (TNY_IS_FOLDER (folder));
1382
1383         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1384         priv->total = 1;
1385         priv->done = 0;
1386         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1387
1388         /* Create the helper */
1389         helper = g_slice_new0 (XFerMsgAsyncHelper);
1390         helper->mail_op = g_object_ref(self);
1391         helper->dest_folder = g_object_ref(folder);
1392         helper->headers = g_object_ref(headers);
1393         helper->user_callback = user_callback;
1394         helper->user_data = user_data;
1395
1396         /* Get source folder */
1397         iter = tny_list_create_iterator (headers);
1398         header = TNY_HEADER (tny_iterator_get_current (iter));
1399         src_folder = tny_header_get_folder (header);
1400         g_object_unref (header);
1401         g_object_unref (iter);
1402
1403         /* Transfer messages */
1404         tny_folder_transfer_msgs_async (src_folder, 
1405                                         headers, 
1406                                         folder, 
1407                                         delete_original, 
1408                                         transfer_msgs_cb, 
1409                                         transfer_msgs_status_cb,
1410                                         helper);
1411 }
1412
1413
1414 static void
1415 on_refresh_folder (TnyFolder   *folder, 
1416                    gboolean     cancelled, 
1417                    GError     **error,
1418                    gpointer     user_data)
1419 {
1420         ModestMailOperation *self;
1421         ModestMailOperationPrivate *priv;
1422
1423         self = MODEST_MAIL_OPERATION (user_data);
1424         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1425
1426         if (*error) {
1427                 priv->error = g_error_copy (*error);
1428                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1429                 goto out;
1430         }
1431
1432         if (cancelled) {
1433                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1434                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1435                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1436                              _("Error trying to refresh the contents of %s"),
1437                              tny_folder_get_name (folder));
1438                 goto out;
1439         }
1440
1441         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1442
1443  out:
1444         /* Free */
1445         g_object_unref (folder);
1446
1447         /* Notify the queue */
1448         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1449 }
1450
1451 static void
1452 on_refresh_folder_status_update (GObject *obj,
1453                                  TnyStatus *status,
1454                                  gpointer user_data)
1455 {
1456         ModestMailOperation *self;
1457         ModestMailOperationPrivate *priv;
1458
1459         g_return_if_fail (status != NULL);
1460         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1461
1462         /* Temporary FIX: useful when tinymail send us status
1463            information *after* calling the function callback */
1464         if (!MODEST_IS_MAIL_OPERATION (user_data))
1465                 return;
1466
1467         self = MODEST_MAIL_OPERATION (user_data);
1468         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1469
1470         priv->done = status->position;
1471         priv->total = status->of_total;
1472
1473         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1474 }
1475
1476 void 
1477 modest_mail_operation_refresh_folder  (ModestMailOperation *self,
1478                                        TnyFolder *folder)
1479 {
1480         ModestMailOperationPrivate *priv;
1481
1482         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1483
1484         /* Pick a reference */
1485         g_object_ref (folder);
1486
1487         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1488
1489         /* Refresh the folder. TODO: tinymail could issue a status
1490            updates before the callback call then this could happen. We
1491            must review the design */
1492         tny_folder_refresh_async (folder,
1493                                   on_refresh_folder,
1494                                   on_refresh_folder_status_update,
1495                                   self);
1496 }
1497
1498 void
1499 _modest_mail_operation_notify_end (ModestMailOperation *self)
1500 {
1501         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1502 }