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