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