* Change mail_operation_new calls tu use the new field 'id'.
[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_folders_cb    (TnyFolderStore *self, 
60                                       TnyList *list, 
61                                       GError **err, 
62                                       gpointer user_data);
63
64 enum _ModestMailOperationSignals 
65 {
66         PROGRESS_CHANGED_SIGNAL,
67
68         NUM_SIGNALS
69 };
70
71 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
72 struct _ModestMailOperationPrivate {
73         guint                      done;
74         guint                      total;
75         ModestMailOperationStatus  status;      
76         ModestMailOperationId      id;          
77         GError                    *error;
78 };
79
80 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
81                                                    MODEST_TYPE_MAIL_OPERATION, \
82                                                    ModestMailOperationPrivate))
83
84 #define CHECK_EXCEPTION(priv, new_status)  if (priv->error) {\
85                                                    priv->status = new_status;\
86                                                }
87
88 typedef struct _RefreshFolderAsyncHelper
89 {
90         ModestMailOperation *mail_op;
91         TnyIterator *iter;
92         guint failed;
93         guint canceled;
94
95 } RefreshFolderAsyncHelper;
96
97 typedef struct _XFerMsgAsyncHelper
98 {
99         ModestMailOperation *mail_op;
100         TnyList *headers;
101         TnyFolder *dest_folder;
102
103 } XFerMsgAsyncHelper;
104
105
106 /* globals */
107 static GObjectClass *parent_class = NULL;
108
109 static guint signals[NUM_SIGNALS] = {0};
110
111 GType
112 modest_mail_operation_get_type (void)
113 {
114         static GType my_type = 0;
115         if (!my_type) {
116                 static const GTypeInfo my_info = {
117                         sizeof(ModestMailOperationClass),
118                         NULL,           /* base init */
119                         NULL,           /* base finalize */
120                         (GClassInitFunc) modest_mail_operation_class_init,
121                         NULL,           /* class finalize */
122                         NULL,           /* class data */
123                         sizeof(ModestMailOperation),
124                         1,              /* n_preallocs */
125                         (GInstanceInitFunc) modest_mail_operation_init,
126                         NULL
127                 };
128                 my_type = g_type_register_static (G_TYPE_OBJECT,
129                                                   "ModestMailOperation",
130                                                   &my_info, 0);
131         }
132         return my_type;
133 }
134
135 static void
136 modest_mail_operation_class_init (ModestMailOperationClass *klass)
137 {
138         GObjectClass *gobject_class;
139         gobject_class = (GObjectClass*) klass;
140
141         parent_class            = g_type_class_peek_parent (klass);
142         gobject_class->finalize = modest_mail_operation_finalize;
143
144         g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
145
146         /**
147          * ModestMailOperation::progress-changed
148          * @self: the #MailOperation that emits the signal
149          * @user_data: user data set when the signal handler was connected
150          *
151          * Emitted when the progress of a mail operation changes
152          */
153         signals[PROGRESS_CHANGED_SIGNAL] = 
154                 g_signal_new ("progress-changed",
155                               G_TYPE_FROM_CLASS (gobject_class),
156                               G_SIGNAL_RUN_FIRST,
157                               G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
158                               NULL, NULL,
159                               g_cclosure_marshal_VOID__VOID,
160                               G_TYPE_NONE, 0);
161 }
162
163 static void
164 modest_mail_operation_init (ModestMailOperation *obj)
165 {
166         ModestMailOperationPrivate *priv;
167
168         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
169
170         priv->status   = MODEST_MAIL_OPERATION_STATUS_INVALID;
171         priv->id       = MODEST_MAIL_OPERATION_ID_UNKNOWN;
172         priv->error    = NULL;
173         priv->done     = 0;
174         priv->total    = 0;
175 }
176
177 static void
178 modest_mail_operation_finalize (GObject *obj)
179 {
180         ModestMailOperationPrivate *priv;
181
182         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
183
184         if (priv->error) {
185                 g_error_free (priv->error);
186                 priv->error = NULL;
187         }
188
189         G_OBJECT_CLASS(parent_class)->finalize (obj);
190 }
191
192 ModestMailOperation*
193 modest_mail_operation_new_with_id (ModestMailOperationId id)
194 {
195         ModestMailOperation *obj;
196         ModestMailOperationPrivate *priv;
197
198
199         obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
200         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
201
202         priv->id = id;
203
204         return obj;
205 }
206
207 ModestMailOperation*
208 modest_mail_operation_new ()
209 {
210         return MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
211 }
212
213
214 ModestMailOperationId
215 modest_mail_operation_get_id (ModestMailOperation *self)
216 {
217         ModestMailOperationPrivate *priv;
218
219         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
220         
221         return priv->id;
222 }
223
224 void
225 modest_mail_operation_send_mail (ModestMailOperation *self,
226                                  TnyTransportAccount *transport_account,
227                                  TnyMsg* msg)
228 {
229         TnySendQueue *send_queue;
230         
231         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
232         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
233         g_return_if_fail (TNY_IS_MSG (msg));
234         
235         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
236         if (!TNY_IS_SEND_QUEUE(send_queue))
237                 g_printerr ("modest: could not find send queue for account\n");
238         else {
239                 GError *err = NULL;
240                 tny_send_queue_add (send_queue, msg, &err);
241                 if (err) {
242                         g_printerr ("modest: error adding msg to send queue: %s\n",
243                                     err->message);
244                         g_error_free (err);
245                 } else
246                         g_message ("modest: message added to send queue");
247         }
248
249         /* Notify the queue */
250         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
251 }
252
253 void
254 modest_mail_operation_send_new_mail (ModestMailOperation *self,
255                                      TnyTransportAccount *transport_account,
256                                      const gchar *from,  const gchar *to,
257                                      const gchar *cc,  const gchar *bcc,
258                                      const gchar *subject, const gchar *plain_body,
259                                      const gchar *html_body,
260                                      const GList *attachments_list,
261                                      TnyHeaderFlags priority_flags)
262 {
263         TnyMsg *new_msg;
264         ModestMailOperationPrivate *priv = NULL;
265         /* GList *node = NULL; */
266
267         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
268         g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
269
270         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
271
272         /* Check parametters */
273         if (to == NULL) {
274                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
275                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
276                              _("Error trying to send a mail. You need to set at least one recipient"));
277                 return;
278         }
279
280         if (html_body == NULL) {
281                 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
282         } else {
283                 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
284         }
285         if (!new_msg) {
286                 g_printerr ("modest: failed to create a new msg\n");
287                 return;
288         }
289
290         /* TODO: add priority handling. It's received in the priority_flags operator, and
291            it should have effect in the sending operation */
292
293         /* Call mail operation */
294         modest_mail_operation_send_mail (self, transport_account, new_msg);
295
296         /* Free */
297         g_object_unref (G_OBJECT (new_msg));
298 }
299
300 static void
301 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
302 {
303         TnyIterator *iter;
304         TnyList *folders = tny_simple_list_new ();
305
306         tny_folder_store_get_folders (store, folders, query, NULL);
307         iter = tny_list_create_iterator (folders);
308
309         while (!tny_iterator_is_done (iter)) {
310
311                 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
312
313                 tny_list_prepend (all_folders, G_OBJECT (folder));
314
315                 recurse_folders (folder, query, all_folders);
316             
317                 g_object_unref (G_OBJECT (folder));
318
319                 tny_iterator_next (iter);
320         }
321          g_object_unref (G_OBJECT (iter));
322          g_object_unref (G_OBJECT (folders));
323 }
324
325 static void
326 update_folders_cb (TnyFolderStore *folder_store, TnyList *list, GError **err, gpointer user_data)
327 {
328         ModestMailOperation *self;
329         ModestMailOperationPrivate *priv;
330         TnyIterator *iter;
331         TnyList *all_folders;
332         
333         self  = MODEST_MAIL_OPERATION (user_data);
334         priv  = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
335
336         g_message (__FUNCTION__);
337         
338         if (*err) {
339                 priv->error = g_error_copy (*err);
340                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
341                 goto out;
342         }
343
344         /* Get all the folders We can do it synchronously because
345            we're already running in a different thread than the UI */
346         all_folders = tny_list_copy (list);
347         iter = tny_list_create_iterator (all_folders);
348         while (!tny_iterator_is_done (iter)) {
349                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
350
351                 recurse_folders (folder, NULL, all_folders);
352                 tny_iterator_next (iter);
353         }
354         g_object_unref (G_OBJECT (iter));
355
356         /* Refresh folders */
357         iter = tny_list_create_iterator (all_folders);
358         priv->total = tny_list_get_length (all_folders);
359
360         while (!tny_iterator_is_done (iter) && !priv->error) {
361
362                 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
363
364                 /* Refresh the folder */
365                 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
366
367                 if (priv->error) {
368                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
369                 } else {        
370                         /* Update status and notify */
371                         priv->done++;
372                         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
373                 }
374     
375                 g_object_unref (G_OBJECT (folder));
376             
377                 tny_iterator_next (iter);
378         }
379
380         g_object_unref (G_OBJECT (iter));
381  out:
382         g_object_unref (G_OBJECT (list));
383
384         /* Check if the operation was a success */
385         if (priv->done == priv->total && !priv->error)
386                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
387
388         /* Free */
389         g_object_unref (G_OBJECT (folder_store));
390
391         /* Notify the queue */
392         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
393 }
394
395 gboolean
396 modest_mail_operation_update_account (ModestMailOperation *self,
397                                       TnyStoreAccount *store_account)
398 {
399         ModestMailOperationPrivate *priv;
400         TnyList *folders;
401
402         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
403         g_return_val_if_fail (TNY_IS_STORE_ACCOUNT(store_account), FALSE);
404
405         /* Pick async call reference */
406         g_object_ref (store_account);
407
408         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
409
410         priv->total = 0;
411         priv->done  = 0;
412         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
413         
414         /* Get subscribed folders & refresh them */
415         folders = TNY_LIST (tny_simple_list_new ());
416
417         g_message ("tny_folder_store_get_folders_async");
418         tny_folder_store_get_folders_async (TNY_FOLDER_STORE (store_account),
419                                             folders, update_folders_cb, NULL, self);
420         
421         return TRUE;
422 }
423
424 ModestMailOperationStatus
425 modest_mail_operation_get_status (ModestMailOperation *self)
426 {
427         ModestMailOperationPrivate *priv;
428
429         g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
430         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
431                               MODEST_MAIL_OPERATION_STATUS_INVALID);
432
433         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
434         return priv->status;
435 }
436
437 const GError *
438 modest_mail_operation_get_error (ModestMailOperation *self)
439 {
440         ModestMailOperationPrivate *priv;
441
442         g_return_val_if_fail (self, NULL);
443         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
444
445         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
446         return priv->error;
447 }
448
449 gboolean 
450 modest_mail_operation_cancel (ModestMailOperation *self)
451 {
452         /* TODO */
453         return TRUE;
454 }
455
456 guint 
457 modest_mail_operation_get_task_done (ModestMailOperation *self)
458 {
459         ModestMailOperationPrivate *priv;
460
461         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
462
463         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
464         return priv->done;
465 }
466
467 guint 
468 modest_mail_operation_get_task_total (ModestMailOperation *self)
469 {
470         ModestMailOperationPrivate *priv;
471
472         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
473
474         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
475         return priv->total;
476 }
477
478 gboolean
479 modest_mail_operation_is_finished (ModestMailOperation *self)
480 {
481         ModestMailOperationPrivate *priv;
482         gboolean retval = FALSE;
483
484         if (!MODEST_IS_MAIL_OPERATION (self)) {
485                 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
486                 return retval;
487         }
488
489         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
490
491         if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS   ||
492             priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED    ||
493             priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED  ||
494             priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
495                 retval = TRUE;
496         } else {
497                 retval = FALSE;
498         }
499
500         return retval;
501 }
502
503 /* ******************************************************************* */
504 /* ************************** STORE  ACTIONS ************************* */
505 /* ******************************************************************* */
506
507
508 TnyFolder *
509 modest_mail_operation_create_folder (ModestMailOperation *self,
510                                      TnyFolderStore *parent,
511                                      const gchar *name)
512 {
513         ModestTnyFolderRules rules;
514         ModestMailOperationPrivate *priv;
515         TnyFolder *new_folder = NULL;
516         gboolean can_create = FALSE;
517
518         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
519         g_return_val_if_fail (name, NULL);
520
521         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
522
523         /* Check parent */
524         if (!TNY_IS_FOLDER (parent)) {
525                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
526                              MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
527                              _("mail_in_ui_folder_create_error"));
528         } else {
529                 /* Check folder rules */
530                 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
531                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
532                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
533                                      MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
534                                      _("mail_in_ui_folder_create_error"));
535                 else
536                         can_create = TRUE;              
537         }
538
539         if (can_create) {
540                 /* Create the folder */
541                 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
542                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
543         }
544
545         /* Notify the queue */
546         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
547
548         return new_folder;
549 }
550
551 void
552 modest_mail_operation_remove_folder (ModestMailOperation *self,
553                                      TnyFolder           *folder,
554                                      gboolean             remove_to_trash)
555 {
556         TnyAccount *account;
557         ModestMailOperationPrivate *priv;
558         ModestTnyFolderRules rules;
559
560         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
561         g_return_if_fail (TNY_IS_FOLDER (folder));
562
563         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
564
565         /* Check folder rules */
566         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
567         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
568                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
569                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
570                              _("mail_in_ui_folder_delete_error"));
571                 goto end;
572         }
573
574         /* Get the account */
575         account = tny_folder_get_account (folder);
576
577         /* Delete folder or move to trash */
578         if (remove_to_trash) {
579                 TnyFolder *trash_folder, *new_folder;
580                 trash_folder = modest_tny_account_get_special_folder (account,
581                                                                       TNY_FOLDER_TYPE_TRASH);
582                 /* TODO: error_handling */
583                 new_folder = modest_mail_operation_xfer_folder (self, folder, 
584                                                                 TNY_FOLDER_STORE (trash_folder), TRUE);
585                 g_object_unref (G_OBJECT (new_folder));
586         } else {
587                 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
588
589                 tny_folder_store_remove_folder (parent, folder, &(priv->error));
590                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
591
592                 if (parent)
593                         g_object_unref (G_OBJECT (parent));
594         }
595         g_object_unref (G_OBJECT (account));
596
597  end:
598         /* Notify the queue */
599         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
600 }
601
602 void
603 modest_mail_operation_rename_folder (ModestMailOperation *self,
604                                      TnyFolder *folder,
605                                      const gchar *name)
606 {
607         ModestMailOperationPrivate *priv;
608         ModestTnyFolderRules rules;
609
610         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
611         g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
612         g_return_if_fail (name);
613
614         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
615
616         /* Check folder rules */
617         rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
618         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
619                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
621                              _("FIXME: unable to rename"));
622         } else {
623                 /* Rename. Camel handles folder subscription/unsubscription */
624                 tny_folder_set_name (folder, name, &(priv->error));
625                 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
626         }
627
628         /* Notify the queue */
629         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
630  }
631
632 TnyFolder *
633 modest_mail_operation_xfer_folder (ModestMailOperation *self,
634                                    TnyFolder *folder,
635                                    TnyFolderStore *parent,
636                                    gboolean delete_original)
637 {
638         ModestMailOperationPrivate *priv;
639         TnyFolder *new_folder = NULL;
640         ModestTnyFolderRules rules;
641
642         g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
643         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
644         g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
645
646         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
647
648         /* The moveable restriction is applied also to copy operation */
649         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
650         if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
651                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
652                              MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
653                              _("FIXME: unable to rename"));
654         } else {
655                 /* Move/Copy folder */
656                 new_folder = tny_folder_copy (folder,
657                                               parent,
658                                               tny_folder_get_name (folder),
659                                               delete_original, 
660                                               &(priv->error));
661         }
662
663         /* Notify the queue */
664         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
665
666         return new_folder;
667 }
668
669
670 /* ******************************************************************* */
671 /* **************************  MSG  ACTIONS  ************************* */
672 /* ******************************************************************* */
673
674 void 
675 modest_mail_operation_remove_msg (ModestMailOperation *self,
676                                   TnyHeader *header,
677                                   gboolean remove_to_trash)
678 {
679         TnyFolder *folder;
680         ModestMailOperationPrivate *priv;
681
682         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
683         g_return_if_fail (TNY_IS_HEADER (header));
684
685         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
686         folder = tny_header_get_folder (header);
687
688         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
689
690         /* Delete or move to trash */
691         if (remove_to_trash) {
692                 TnyFolder *trash_folder;
693                 TnyStoreAccount *store_account;
694
695                 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
696                 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
697                                                                       TNY_FOLDER_TYPE_TRASH);
698                 if (trash_folder) {
699                         TnyList *headers;
700
701                         /* Create list */
702                         headers = tny_simple_list_new ();
703                         tny_list_append (headers, G_OBJECT (header));
704                         g_object_unref (header);
705
706                         /* Move to trash */
707                         modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
708                         g_object_unref (headers);
709 /*                      g_object_unref (trash_folder); */
710                 } else {
711                         ModestMailOperationPrivate *priv;
712
713                         /* Set status failed and set an error */
714                         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
715                         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
716                         g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
717                                      MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
718                                      _("Error trying to delete a message. Trash folder not found"));
719                 }
720
721                 g_object_unref (G_OBJECT (store_account));
722         } else {
723                 tny_folder_remove_msg (folder, header, &(priv->error));
724                 if (!priv->error)
725                         tny_folder_sync(folder, TRUE, &(priv->error));
726         }
727
728         /* Set status */
729         if (!priv->error)
730                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
731         else
732                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
733
734         /* Free */
735         g_object_unref (G_OBJECT (folder));
736
737         /* Notify the queue */
738         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
739 }
740
741 static void
742 transfer_msgs_cb (TnyFolder *folder, GError **err, gpointer user_data)
743 {
744         XFerMsgAsyncHelper *helper;
745         ModestMailOperation *self;
746         ModestMailOperationPrivate *priv;
747
748         helper = (XFerMsgAsyncHelper *) user_data;
749         self = helper->mail_op;
750         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
751
752         if (*err) {
753                 priv->error = g_error_copy (*err);
754                 priv->done = 0;
755                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
756         } else {
757                 priv->done = 1;
758                 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
759         }
760
761         /* Free */
762         g_object_unref (helper->headers);
763         g_object_unref (helper->dest_folder);
764         g_object_unref (folder);
765         g_free (helper);
766
767         /* Notify the queue */
768         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
769 }
770
771 void
772 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
773                                  TnyList *headers, 
774                                  TnyFolder *folder, 
775                                  gboolean delete_original)
776 {
777         ModestMailOperationPrivate *priv;
778         TnyIterator *iter;
779         TnyFolder *src_folder;
780         XFerMsgAsyncHelper *helper;
781         TnyHeader *header;
782
783         g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
784         g_return_if_fail (TNY_IS_LIST (headers));
785         g_return_if_fail (TNY_IS_FOLDER (folder));
786
787         /* Pick references for async calls */
788         g_object_ref (folder);
789
790         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
791         priv->total = 1;
792         priv->done = 0;
793         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
794
795         /* Create the helper */
796         helper = g_malloc0 (sizeof (XFerMsgAsyncHelper));
797         helper->mail_op = self;
798         helper->dest_folder = folder;
799         helper->headers = headers;
800
801         /* Get source folder */
802         iter = tny_list_create_iterator (headers);
803         header = TNY_HEADER (tny_iterator_get_current (iter));
804         src_folder = tny_header_get_folder (header);
805         g_object_unref (header);
806         g_object_unref (iter);
807
808         /* Transfer messages */
809         tny_folder_transfer_msgs_async (src_folder, 
810                                         headers, 
811                                         folder, 
812                                         delete_original, 
813                                         transfer_msgs_cb, 
814                                         helper);
815 }
816
817 static void
818 on_refresh_folder (TnyFolder   *folder, 
819                    gboolean     cancelled, 
820                    GError     **error,
821                    gpointer     user_data)
822 {
823         ModestMailOperation *self;
824         ModestMailOperationPrivate *priv;
825
826         self = MODEST_MAIL_OPERATION (user_data);
827         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
828
829         if (*error) {
830                 priv->error = g_error_copy (*error);
831                 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
832                 goto out;
833         }
834
835         if (cancelled) {
836                 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
837                 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
838                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
839                              _("Error trying to refresh the contents of %s"),
840                              tny_folder_get_name (folder));
841                 goto out;
842         }
843
844         priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
845
846  out:
847         /* Free */
848         g_object_unref (folder);
849
850         /* Notify the queue */
851         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
852 }
853
854 static void
855 on_refresh_folder_status_update (GObject *obj,
856                                  TnyStatus *status,  
857                                  gpointer user_data)
858 {
859         ModestMailOperation *self;
860         ModestMailOperationPrivate *priv;
861
862         g_return_if_fail (status != NULL);
863         g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
864
865         self = MODEST_MAIL_OPERATION (user_data);
866         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
867
868         priv->done = status->position;
869         priv->total = status->of_total;
870
871         if (priv->done == 1 && priv->total == 100)
872                 return;
873
874         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
875 }
876
877 void 
878 modest_mail_operation_refresh_folder  (ModestMailOperation *self,
879                                        TnyFolder *folder)
880 {
881         ModestMailOperationPrivate *priv;
882
883         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
884
885         /* Pick a reference */
886         g_object_ref (folder);
887
888         priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
889
890         /* Refresh the folder. TODO: tinymail could issue a status
891            updates before the callback call then this could happen. We
892            must review the design */
893         tny_folder_refresh_async (folder,
894                                   on_refresh_folder,
895                                   on_refresh_folder_status_update,
896 /*                                NULL, */
897                                   self);
898 }
899
900 void
901 _modest_mail_operation_notify_end (ModestMailOperation *self)
902 {
903         g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
904 }