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