1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
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"
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);
59 static void update_process_msg_status_cb (GObject *obj,
62 static void get_msg_cb (TnyFolder *folder,
68 static void get_msg_status_cb (GObject *obj,
73 enum _ModestMailOperationSignals
75 PROGRESS_CHANGED_SIGNAL,
80 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
81 struct _ModestMailOperationPrivate {
84 ModestMailOperationStatus status;
85 ModestMailOperationId id;
90 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
91 MODEST_TYPE_MAIL_OPERATION, \
92 ModestMailOperationPrivate))
94 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
95 priv->status = new_status;\
98 typedef struct _GetMsgAsyncHelper {
99 ModestMailOperation *mail_op;
100 GetMsgAsynUserCallback user_callback;
105 typedef struct _RefreshFolderAsyncHelper
107 ModestMailOperation *mail_op;
112 } RefreshFolderAsyncHelper;
114 typedef struct _XFerMsgAsyncHelper
116 ModestMailOperation *mail_op;
118 TnyFolder *dest_folder;
120 } XFerMsgAsyncHelper;
122 typedef struct _XFerFolderAsyncHelper
124 ModestMailOperation *mail_op;
126 } XFerFolderAsyncHelper;
130 static GObjectClass *parent_class = NULL;
132 static guint signals[NUM_SIGNALS] = {0};
135 modest_mail_operation_get_type (void)
137 static GType my_type = 0;
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),
148 (GInstanceInitFunc) modest_mail_operation_init,
151 my_type = g_type_register_static (G_TYPE_OBJECT,
152 "ModestMailOperation",
159 modest_mail_operation_class_init (ModestMailOperationClass *klass)
161 GObjectClass *gobject_class;
162 gobject_class = (GObjectClass*) klass;
164 parent_class = g_type_class_peek_parent (klass);
165 gobject_class->finalize = modest_mail_operation_finalize;
167 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
170 * ModestMailOperation::progress-changed
171 * @self: the #MailOperation that emits the signal
172 * @user_data: user data set when the signal handler was connected
174 * Emitted when the progress of a mail operation changes
176 signals[PROGRESS_CHANGED_SIGNAL] =
177 g_signal_new ("progress-changed",
178 G_TYPE_FROM_CLASS (gobject_class),
180 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
182 g_cclosure_marshal_VOID__VOID,
187 modest_mail_operation_init (ModestMailOperation *obj)
189 ModestMailOperationPrivate *priv;
191 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
193 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
194 priv->id = MODEST_MAIL_OPERATION_ID_UNKNOWN;
202 modest_mail_operation_finalize (GObject *obj)
204 ModestMailOperationPrivate *priv;
206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
209 g_error_free (priv->error);
213 g_object_unref (priv->source);
217 G_OBJECT_CLASS(parent_class)->finalize (obj);
221 modest_mail_operation_new (ModestMailOperationId id,
224 ModestMailOperation *obj;
225 ModestMailOperationPrivate *priv;
227 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
228 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
232 priv->source = g_object_ref(source);
238 ModestMailOperationId
239 modest_mail_operation_get_id (ModestMailOperation *self)
241 ModestMailOperationPrivate *priv;
243 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
249 modest_mail_operation_is_mine (ModestMailOperation *self,
252 ModestMailOperationPrivate *priv;
254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
255 if (priv->source == NULL) return FALSE;
257 return priv->source == me;
262 modest_mail_operation_send_mail (ModestMailOperation *self,
263 TnyTransportAccount *transport_account,
266 TnySendQueue *send_queue;
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));
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");
277 tny_send_queue_add (send_queue, msg, &err);
279 g_printerr ("modest: error adding msg to send queue: %s\n",
283 /* g_message ("modest: message added to send queue"); */
287 /* Notify the queue */
288 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
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)
302 ModestMailOperationPrivate *priv = NULL;
303 /* GList *node = NULL; */
305 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
306 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
310 /* Check parametters */
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"));
318 if (html_body == NULL) {
319 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
321 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
324 g_printerr ("modest: failed to create a new msg\n");
328 /* TODO: add priority handling. It's received in the priority_flags operator, and
329 it should have effect in the sending operation */
331 /* Call mail operation */
332 modest_mail_operation_send_mail (self, transport_account, new_msg);
335 g_object_unref (G_OBJECT (new_msg));
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)
349 TnyFolder *folder = NULL;
350 ModestMailOperationPrivate *priv = NULL;
353 /* GList *node = NULL; */
355 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
356 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
360 if (html_body == NULL) {
361 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
363 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
366 g_printerr ("modest: failed to create a new msg\n");
370 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
372 g_printerr ("modest: failed to find Drafts folder\n");
376 tny_folder_add_msg (folder, msg, &err);
378 g_printerr ("modest: error adding msg to Drafts folder: %s",
384 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
389 g_object_unref (G_OBJECT(msg));
391 g_object_unref (G_OBJECT(folder));
396 ModestMailOperation *mail_op;
397 TnyStoreAccount *account;
402 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
405 TnyList *folders = tny_simple_list_new ();
407 tny_folder_store_get_folders (store, folders, query, NULL);
408 iter = tny_list_create_iterator (folders);
410 while (!tny_iterator_is_done (iter)) {
412 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
414 tny_list_prepend (all_folders, G_OBJECT (folder));
415 recurse_folders (folder, query, all_folders);
416 g_object_unref (G_OBJECT (folder));
418 tny_iterator_next (iter);
420 g_object_unref (G_OBJECT (iter));
421 g_object_unref (G_OBJECT (folders));
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
429 notify_update_account_observers (gpointer data)
431 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
433 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
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
443 notify_update_account_queue (gpointer data)
445 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
447 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
449 g_object_unref (mail_op);
455 update_account_thread (gpointer thr_user_data)
457 UpdateAccountInfo *info;
458 TnyList *all_folders = NULL;
459 TnyIterator *iter = NULL;
460 TnyFolderStoreQuery *query = NULL;
461 ModestMailOperationPrivate *priv;
464 info = (UpdateAccountInfo *) thr_user_data;
465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
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),
477 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
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));
485 recurse_folders (folder, query, all_folders);
486 tny_iterator_next (iter);
488 g_object_unref (G_OBJECT (iter));
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);
498 /* Refresh folders */
499 iter = tny_list_create_iterator (all_folders);
500 while (!tny_iterator_is_done (iter) && !priv->error) {
502 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
504 /* Refresh the folder */
505 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
508 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
511 g_object_unref (G_OBJECT (folder));
512 tny_iterator_next (iter);
514 g_object_unref (G_OBJECT (iter));
515 g_source_remove (timeout);
517 /* Check if the operation was a success */
519 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
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,
530 /* Notify the queue */
531 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
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);
544 modest_mail_operation_update_account (ModestMailOperation *self,
545 const gchar *account_name)
548 UpdateAccountInfo *info;
549 ModestMailOperationPrivate *priv;
550 TnyStoreAccount *modest_account;
552 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
553 g_return_val_if_fail (account_name, FALSE);
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);
561 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
563 /* Get the Modest account */
564 modest_account = (TnyStoreAccount *)
565 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
567 TNY_ACCOUNT_TYPE_STORE);
569 if (!modest_account) {
570 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
571 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
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;
582 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
587 ModestMailOperationStatus
588 modest_mail_operation_get_status (ModestMailOperation *self)
590 ModestMailOperationPrivate *priv;
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);
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
601 modest_mail_operation_get_error (ModestMailOperation *self)
603 ModestMailOperationPrivate *priv;
605 g_return_val_if_fail (self, NULL);
606 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
613 modest_mail_operation_cancel (ModestMailOperation *self)
615 ModestMailOperationPrivate *priv;
617 if (!MODEST_IS_MAIL_OPERATION (self)) {
618 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
622 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
624 /* TODO: Tinymail does not support cancel operation */
627 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
629 /* Notify the queue */
630 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
636 modest_mail_operation_get_task_done (ModestMailOperation *self)
638 ModestMailOperationPrivate *priv;
640 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
642 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
647 modest_mail_operation_get_task_total (ModestMailOperation *self)
649 ModestMailOperationPrivate *priv;
651 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
653 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
658 modest_mail_operation_is_finished (ModestMailOperation *self)
660 ModestMailOperationPrivate *priv;
661 gboolean retval = FALSE;
663 if (!MODEST_IS_MAIL_OPERATION (self)) {
664 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
668 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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) {
682 /* ******************************************************************* */
683 /* ************************** STORE ACTIONS ************************* */
684 /* ******************************************************************* */
688 modest_mail_operation_create_folder (ModestMailOperation *self,
689 TnyFolderStore *parent,
692 ModestTnyFolderRules rules;
693 ModestMailOperationPrivate *priv;
694 TnyFolder *new_folder = NULL;
695 gboolean can_create = FALSE;
697 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
698 g_return_val_if_fail (name, NULL);
700 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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"));
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"));
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);
724 /* Notify the queue */
725 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
731 modest_mail_operation_remove_folder (ModestMailOperation *self,
733 gboolean remove_to_trash)
736 ModestMailOperationPrivate *priv;
737 ModestTnyFolderRules rules;
739 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
740 g_return_if_fail (TNY_IS_FOLDER (folder));
742 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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"));
753 /* Get the account */
754 account = tny_folder_get_account (folder);
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)); */
769 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
771 tny_folder_store_remove_folder (parent, folder, &(priv->error));
772 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
775 g_object_unref (G_OBJECT (parent));
777 g_object_unref (G_OBJECT (account));
780 /* Notify the queue */
781 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
785 modest_mail_operation_rename_folder (ModestMailOperation *self,
789 ModestMailOperationPrivate *priv;
790 ModestTnyFolderRules rules;
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);
796 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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"));
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);
810 /* Notify the queue */
811 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
815 transfer_folder_status_cb (GObject *obj,
819 XFerMsgAsyncHelper *helper = NULL;
820 ModestMailOperation *self;
821 ModestMailOperationPrivate *priv;
823 g_return_if_fail (status != NULL);
824 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
826 helper = (XFerMsgAsyncHelper *) user_data;
827 g_return_if_fail (helper != NULL);
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))
834 self = helper->mail_op;
835 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
837 if ((status->position == 1) && (status->of_total == 100))
840 priv->done = status->position;
841 priv->total = status->of_total;
844 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
849 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
851 XFerFolderAsyncHelper *helper = NULL;
852 ModestMailOperation *self = NULL;
853 ModestMailOperationPrivate *priv = NULL;
855 helper = (XFerFolderAsyncHelper *) user_data;
856 self = helper->mail_op;
858 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
861 priv->error = g_error_copy (*err);
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));
872 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
876 g_slice_free (XFerFolderAsyncHelper, helper);
877 g_object_unref (folder);
878 g_object_unref (into);
879 g_object_unref (new_folder);
881 /* Notify the queue */
882 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
886 modest_mail_operation_xfer_folder (ModestMailOperation *self,
888 TnyFolderStore *parent,
889 gboolean delete_original)
891 ModestMailOperationPrivate *priv;
892 TnyFolder *new_folder = NULL;
893 ModestTnyFolderRules rules;
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);
899 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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"));
908 /* Move/Copy folder */
909 new_folder = tny_folder_copy (folder,
911 tny_folder_get_name (folder),
916 /* Notify the queue */
917 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
923 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
925 TnyFolderStore *parent,
926 gboolean delete_original)
928 XFerFolderAsyncHelper *helper = NULL;
929 ModestMailOperationPrivate *priv = NULL;
930 ModestTnyFolderRules rules;
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));
936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
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"));
945 helper = g_slice_new0 (XFerFolderAsyncHelper);
946 helper->mail_op = self;
948 /* Move/Copy folder */
949 tny_folder_copy_async (folder,
951 tny_folder_get_name (folder),
954 transfer_folder_status_cb,
960 /* ******************************************************************* */
961 /* ************************** MSG ACTIONS ************************* */
962 /* ******************************************************************* */
964 void modest_mail_operation_get_msg (ModestMailOperation *self,
966 GetMsgAsynUserCallback user_callback,
969 GetMsgAsyncHelper *helper = NULL;
971 ModestMailOperationPrivate *priv;
973 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
974 g_return_if_fail (TNY_IS_HEADER (header));
976 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
977 folder = tny_header_get_folder (header);
979 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
981 /* Get message from 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;
989 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
991 g_object_unref (G_OBJECT (folder));
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"));
1002 get_msg_cb (TnyFolder *folder,
1008 GetMsgAsyncHelper *helper = NULL;
1009 ModestMailOperation *self = NULL;
1010 ModestMailOperationPrivate *priv = NULL;
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);
1018 helper->pending_ops--;
1020 /* Check errors and cancel */
1022 priv->error = g_error_copy (*error);
1023 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
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));
1035 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
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);
1044 if (helper->pending_ops == 0) {
1045 g_slice_free (GetMsgAsyncHelper, helper);
1047 /* Notify the queue */
1048 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1053 get_msg_status_cb (GObject *obj,
1057 GetMsgAsyncHelper *helper = NULL;
1058 ModestMailOperation *self;
1059 ModestMailOperationPrivate *priv;
1061 g_return_if_fail (status != NULL);
1062 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1064 helper = (GetMsgAsyncHelper *) user_data;
1065 g_return_if_fail (helper != NULL);
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))
1072 self = helper->mail_op;
1073 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1075 if ((status->position == 1) && (status->of_total == 100))
1081 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1085 void modest_mail_operation_process_msg (ModestMailOperation *self,
1086 TnyList *header_list,
1087 GetMsgAsynUserCallback user_callback,
1090 ModestMailOperationPrivate *priv = NULL;
1091 GetMsgAsyncHelper *helper = NULL;
1092 TnyHeader *header = NULL;
1093 TnyFolder *folder = NULL;
1094 TnyIterator *iter = NULL;
1096 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1099 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1101 iter = tny_list_create_iterator (header_list);
1103 priv->total = tny_list_get_length(header_list);
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;
1111 while (!tny_iterator_is_done (iter)) {
1113 header = TNY_HEADER (tny_iterator_get_current (iter));
1114 folder = tny_header_get_folder (header);
1116 /* Get message from 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));
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"));
1128 /* Notify the queue */
1129 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1132 g_slice_free (GetMsgAsyncHelper, helper);
1136 g_object_unref (header);
1137 tny_iterator_next (iter);
1142 update_process_msg_status_cb (GObject *obj,
1146 GetMsgAsyncHelper *helper = NULL;
1147 ModestMailOperation *self;
1148 ModestMailOperationPrivate *priv;
1150 g_return_if_fail (status != NULL);
1151 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1153 helper = (GetMsgAsyncHelper *) user_data;
1154 g_return_if_fail (helper != NULL);
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))
1161 self = helper->mail_op;
1162 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1164 if ((status->position == 1) && (status->of_total == 100))
1167 if (status->of_total > 0)
1168 priv->done += status->position/status->of_total;
1170 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1176 modest_mail_operation_remove_msg (ModestMailOperation *self,
1178 gboolean remove_to_trash)
1181 ModestMailOperationPrivate *priv;
1183 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1184 g_return_if_fail (TNY_IS_HEADER (header));
1186 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1187 folder = tny_header_get_folder (header);
1189 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1191 /* Delete or move to trash */
1192 if (remove_to_trash) {
1193 TnyFolder *trash_folder;
1194 TnyStoreAccount *store_account;
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);
1203 headers = tny_simple_list_new ();
1204 tny_list_append (headers, G_OBJECT (header));
1205 g_object_unref (header);
1208 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1209 g_object_unref (headers);
1210 /* g_object_unref (trash_folder); */
1212 ModestMailOperationPrivate *priv;
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"));
1222 g_object_unref (G_OBJECT (store_account));
1224 tny_folder_remove_msg (folder, header, &(priv->error));
1226 tny_folder_sync(folder, TRUE, &(priv->error));
1231 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1233 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1236 g_object_unref (G_OBJECT (folder));
1238 /* Notify the queue */
1239 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1243 transfer_msgs_status_cb (GObject *obj,
1247 XFerMsgAsyncHelper *helper = NULL;
1248 ModestMailOperation *self;
1249 ModestMailOperationPrivate *priv;
1251 g_return_if_fail (status != NULL);
1252 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1254 helper = (XFerMsgAsyncHelper *) user_data;
1255 g_return_if_fail (helper != NULL);
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))
1262 self = helper->mail_op;
1263 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1265 if ((status->position == 1) && (status->of_total == 100))
1268 priv->done = status->position;
1269 priv->total = status->of_total;
1271 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1276 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1278 XFerMsgAsyncHelper *helper;
1279 ModestMailOperation *self;
1280 ModestMailOperationPrivate *priv;
1282 helper = (XFerMsgAsyncHelper *) user_data;
1283 self = helper->mail_op;
1285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1288 priv->error = g_error_copy (*err);
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));
1299 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
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);
1309 /* Notify the queue */
1310 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1314 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1317 gboolean delete_original)
1319 ModestMailOperationPrivate *priv;
1321 TnyFolder *src_folder;
1322 XFerMsgAsyncHelper *helper;
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));
1329 /* Pick references for async calls */
1330 g_object_ref (folder);
1332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1335 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
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);
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);
1350 /* Transfer messages */
1351 tny_folder_transfer_msgs_async (src_folder,
1356 transfer_msgs_status_cb,
1362 on_refresh_folder (TnyFolder *folder,
1367 ModestMailOperation *self;
1368 ModestMailOperationPrivate *priv;
1370 self = MODEST_MAIL_OPERATION (user_data);
1371 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1374 priv->error = g_error_copy (*error);
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
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));
1388 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1392 g_object_unref (folder);
1394 /* Notify the queue */
1395 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1399 on_refresh_folder_status_update (GObject *obj,
1403 ModestMailOperation *self;
1404 ModestMailOperationPrivate *priv;
1406 g_return_if_fail (status != NULL);
1407 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1409 /* Temporary FIX: useful when tinymail send us status
1410 information *after* calling the function callback */
1411 if (!MODEST_IS_MAIL_OPERATION (user_data))
1414 self = MODEST_MAIL_OPERATION (user_data);
1415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1417 priv->done = status->position;
1418 priv->total = status->of_total;
1420 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1424 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1427 ModestMailOperationPrivate *priv;
1429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1431 /* Pick a reference */
1432 g_object_ref (folder);
1434 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
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,
1441 on_refresh_folder_status_update,
1446 _modest_mail_operation_notify_end (ModestMailOperation *self)
1448 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);