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);
434 g_object_unref (mail_op);
440 * Used by update_account_thread to notify the queue from the main
441 * loop. We call it inside an idle call to achieve that
444 notify_update_account_queue (gpointer data)
446 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
448 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
450 g_object_unref (mail_op);
456 update_account_thread (gpointer thr_user_data)
458 UpdateAccountInfo *info;
459 TnyList *all_folders = NULL;
460 TnyIterator *iter = NULL;
461 TnyFolderStoreQuery *query = NULL;
462 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 priv->total = tny_list_get_length (all_folders);
493 /* Refresh folders */
494 iter = tny_list_create_iterator (all_folders);
495 while (!tny_iterator_is_done (iter) && !priv->error) {
497 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
499 /* Refresh the folder */
500 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
504 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
506 /* Update status and notify. We need to call
507 the notification with an idle in order to
508 call it from the main loop. We need that in
509 order not to get into trouble with Gtk+ */
511 g_idle_add (notify_update_account_observers, g_object_ref (info->mail_op));
514 g_object_unref (G_OBJECT (folder));
515 tny_iterator_next (iter);
517 g_object_unref (G_OBJECT (iter));
519 /* Check if the operation was a success */
520 if (priv->done == priv->total && !priv->error)
521 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
524 /* Notify the queue */
525 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
528 g_object_unref (query);
529 g_object_unref (all_folders);
530 g_object_unref (info->mail_op);
531 g_object_unref (info->account);
532 g_slice_free (UpdateAccountInfo, info);
538 modest_mail_operation_update_account (ModestMailOperation *self,
539 TnyStoreAccount *store_account)
542 UpdateAccountInfo *info;
543 ModestMailOperationPrivate *priv;
545 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
546 g_return_val_if_fail (TNY_IS_STORE_ACCOUNT(store_account), FALSE);
548 /* Init mail operation */
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
552 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
554 /* Create the helper object */
555 info = g_slice_new (UpdateAccountInfo);
556 info->mail_op = g_object_ref (self);
557 info->account = g_object_ref (store_account);
558 info->user_data = NULL;
560 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
565 ModestMailOperationStatus
566 modest_mail_operation_get_status (ModestMailOperation *self)
568 ModestMailOperationPrivate *priv;
570 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
571 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
572 MODEST_MAIL_OPERATION_STATUS_INVALID);
574 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
579 modest_mail_operation_get_error (ModestMailOperation *self)
581 ModestMailOperationPrivate *priv;
583 g_return_val_if_fail (self, NULL);
584 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
591 modest_mail_operation_cancel (ModestMailOperation *self)
593 ModestMailOperationPrivate *priv;
595 if (!MODEST_IS_MAIL_OPERATION (self)) {
596 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
602 /* TODO: Tinymail does not support cancel operation */
605 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
607 /* Notify the queue */
608 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
614 modest_mail_operation_get_task_done (ModestMailOperation *self)
616 ModestMailOperationPrivate *priv;
618 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
620 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
625 modest_mail_operation_get_task_total (ModestMailOperation *self)
627 ModestMailOperationPrivate *priv;
629 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
631 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
636 modest_mail_operation_is_finished (ModestMailOperation *self)
638 ModestMailOperationPrivate *priv;
639 gboolean retval = FALSE;
641 if (!MODEST_IS_MAIL_OPERATION (self)) {
642 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
648 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
649 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
650 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
651 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
660 /* ******************************************************************* */
661 /* ************************** STORE ACTIONS ************************* */
662 /* ******************************************************************* */
666 modest_mail_operation_create_folder (ModestMailOperation *self,
667 TnyFolderStore *parent,
670 ModestTnyFolderRules rules;
671 ModestMailOperationPrivate *priv;
672 TnyFolder *new_folder = NULL;
673 gboolean can_create = FALSE;
675 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
676 g_return_val_if_fail (name, NULL);
678 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
681 if (!TNY_IS_FOLDER (parent)) {
682 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
683 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
684 _("mail_in_ui_folder_create_error"));
686 /* Check folder rules */
687 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
688 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
689 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
690 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
691 _("mail_in_ui_folder_create_error"));
697 /* Create the folder */
698 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
699 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
702 /* Notify the queue */
703 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
709 modest_mail_operation_remove_folder (ModestMailOperation *self,
711 gboolean remove_to_trash)
714 ModestMailOperationPrivate *priv;
715 ModestTnyFolderRules rules;
717 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
718 g_return_if_fail (TNY_IS_FOLDER (folder));
720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
722 /* Check folder rules */
723 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
724 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
725 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
726 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
727 _("mail_in_ui_folder_delete_error"));
731 /* Get the account */
732 account = tny_folder_get_account (folder);
734 /* Delete folder or move to trash */
735 if (remove_to_trash) {
736 TnyFolder *trash_folder = NULL;
737 /* TnyFolder *trash_folder, *new_folder; */
738 trash_folder = modest_tny_account_get_special_folder (account,
739 TNY_FOLDER_TYPE_TRASH);
740 /* TODO: error_handling */
741 modest_mail_operation_xfer_folder (self, folder,
742 TNY_FOLDER_STORE (trash_folder), TRUE);
743 /* new_folder = modest_mail_operation_xfer_folder (self, folder, */
744 /* TNY_FOLDER_STORE (trash_folder), TRUE); */
745 /* g_object_unref (G_OBJECT (new_folder)); */
747 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
749 tny_folder_store_remove_folder (parent, folder, &(priv->error));
750 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
753 g_object_unref (G_OBJECT (parent));
755 g_object_unref (G_OBJECT (account));
758 /* Notify the queue */
759 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
763 modest_mail_operation_rename_folder (ModestMailOperation *self,
767 ModestMailOperationPrivate *priv;
768 ModestTnyFolderRules rules;
770 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
771 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
772 g_return_if_fail (name);
774 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
776 /* Check folder rules */
777 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
778 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
779 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
780 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
781 _("FIXME: unable to rename"));
783 /* Rename. Camel handles folder subscription/unsubscription */
784 tny_folder_set_name (folder, name, &(priv->error));
785 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
788 /* Notify the queue */
789 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
793 transfer_folder_status_cb (GObject *obj,
797 XFerMsgAsyncHelper *helper = NULL;
798 ModestMailOperation *self;
799 ModestMailOperationPrivate *priv;
801 g_return_if_fail (status != NULL);
802 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
804 helper = (XFerMsgAsyncHelper *) user_data;
805 g_return_if_fail (helper != NULL);
807 /* Temporary FIX: useful when tinymail send us status
808 information *after* calling the function callback */
809 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
812 self = helper->mail_op;
813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
815 if ((status->position == 1) && (status->of_total == 100))
818 priv->done = status->position;
819 priv->total = status->of_total;
822 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
827 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, const gchar *new_name, gboolean cancelled, GError **err, gpointer user_data)
829 XFerFolderAsyncHelper *helper = NULL;
830 ModestMailOperation *self = NULL;
831 ModestMailOperationPrivate *priv = NULL;
833 helper = (XFerFolderAsyncHelper *) user_data;
834 self = helper->mail_op;
836 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
839 priv->error = g_error_copy (*err);
841 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
842 } else if (cancelled) {
843 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
844 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
845 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
846 _("Error trying to refresh the contents of %s"),
847 tny_folder_get_name (folder));
850 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
854 g_slice_free (XFerFolderAsyncHelper, helper);
855 g_object_unref (folder);
856 g_object_unref (into);
858 /* Notify the queue */
859 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
863 modest_mail_operation_xfer_folder (ModestMailOperation *self,
865 TnyFolderStore *parent,
866 gboolean delete_original)
868 ModestMailOperationPrivate *priv;
869 TnyFolder *new_folder = NULL;
870 ModestTnyFolderRules rules;
872 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
873 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
874 g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
876 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
878 /* The moveable restriction is applied also to copy operation */
879 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
880 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
881 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
882 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
883 _("FIXME: unable to rename"));
885 /* Move/Copy folder */
886 new_folder = tny_folder_copy (folder,
888 tny_folder_get_name (folder),
893 /* Notify the queue */
894 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
900 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
902 TnyFolderStore *parent,
903 gboolean delete_original)
905 XFerFolderAsyncHelper *helper = NULL;
906 ModestMailOperationPrivate *priv = NULL;
907 ModestTnyFolderRules rules;
909 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
910 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
911 g_return_if_fail (TNY_IS_FOLDER (folder));
913 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
915 /* The moveable restriction is applied also to copy operation */
916 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
917 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
918 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
919 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
920 _("FIXME: unable to rename"));
922 helper = g_slice_new0 (XFerFolderAsyncHelper);
923 helper->mail_op = self;
925 /* Move/Copy folder */
926 tny_folder_copy_async (folder,
928 tny_folder_get_name (folder),
931 transfer_folder_status_cb,
937 /* ******************************************************************* */
938 /* ************************** MSG ACTIONS ************************* */
939 /* ******************************************************************* */
941 void modest_mail_operation_get_msg (ModestMailOperation *self,
943 GetMsgAsynUserCallback user_callback,
946 GetMsgAsyncHelper *helper = NULL;
948 ModestMailOperationPrivate *priv;
950 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
951 g_return_if_fail (TNY_IS_HEADER (header));
953 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
954 folder = tny_header_get_folder (header);
956 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
958 /* Get message from folder */
960 helper = g_slice_new0 (GetMsgAsyncHelper);
961 helper->mail_op = self;
962 helper->user_callback = user_callback;
963 helper->pending_ops = 1;
964 helper->user_data = user_data;
966 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
968 g_object_unref (G_OBJECT (folder));
970 /* Set status failed and set an error */
971 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
972 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
973 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
974 _("Error trying to get a message. No folder found for header"));
979 get_msg_cb (TnyFolder *folder,
985 GetMsgAsyncHelper *helper = NULL;
986 ModestMailOperation *self = NULL;
987 ModestMailOperationPrivate *priv = NULL;
989 helper = (GetMsgAsyncHelper *) user_data;
990 g_return_if_fail (helper != NULL);
991 self = helper->mail_op;
992 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
993 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
995 helper->pending_ops--;
997 /* Check errors and cancel */
999 priv->error = g_error_copy (*error);
1000 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1004 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1005 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1006 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1007 _("Error trying to refresh the contents of %s"),
1008 tny_folder_get_name (folder));
1012 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1014 /* If user defined callback function was defined, call it */
1015 if (helper->user_callback) {
1016 helper->user_callback (priv->source, msg, helper->user_data);
1021 if (helper->pending_ops == 0) {
1022 g_slice_free (GetMsgAsyncHelper, helper);
1024 /* Notify the queue */
1025 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1030 get_msg_status_cb (GObject *obj,
1034 GetMsgAsyncHelper *helper = NULL;
1035 ModestMailOperation *self;
1036 ModestMailOperationPrivate *priv;
1038 g_return_if_fail (status != NULL);
1039 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1041 helper = (GetMsgAsyncHelper *) user_data;
1042 g_return_if_fail (helper != NULL);
1044 /* Temporary FIX: useful when tinymail send us status
1045 information *after* calling the function callback */
1046 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1049 self = helper->mail_op;
1050 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1052 if ((status->position == 1) && (status->of_total == 100))
1058 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1062 void modest_mail_operation_process_msg (ModestMailOperation *self,
1063 TnyList *header_list,
1064 GetMsgAsynUserCallback user_callback,
1067 ModestMailOperationPrivate *priv = NULL;
1068 GetMsgAsyncHelper *helper = NULL;
1069 TnyHeader *header = NULL;
1070 TnyFolder *folder = NULL;
1071 TnyIterator *iter = NULL;
1073 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1075 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1076 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1078 iter = tny_list_create_iterator (header_list);
1080 priv->total = tny_list_get_length(header_list);
1082 helper = g_slice_new0 (GetMsgAsyncHelper);
1083 helper->mail_op = self;
1084 helper->user_callback = user_callback;
1085 helper->pending_ops = priv->total;
1086 helper->user_data = user_data;
1088 while (!tny_iterator_is_done (iter)) {
1090 header = TNY_HEADER (tny_iterator_get_current (iter));
1091 folder = tny_header_get_folder (header);
1093 /* Get message from folder */
1095 /* The callback will call it per each header */
1096 tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1097 g_object_unref (G_OBJECT (folder));
1099 /* Set status failed and set an error */
1100 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1101 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1102 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1103 _("Error trying to get a message. No folder found for header"));
1105 /* Notify the queue */
1106 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1109 g_slice_free (GetMsgAsyncHelper, helper);
1113 g_object_unref (header);
1114 tny_iterator_next (iter);
1119 update_process_msg_status_cb (GObject *obj,
1123 GetMsgAsyncHelper *helper = NULL;
1124 ModestMailOperation *self;
1125 ModestMailOperationPrivate *priv;
1127 g_return_if_fail (status != NULL);
1128 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1130 helper = (GetMsgAsyncHelper *) user_data;
1131 g_return_if_fail (helper != NULL);
1133 /* Temporary FIX: useful when tinymail send us status
1134 information *after* calling the function callback */
1135 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1138 self = helper->mail_op;
1139 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1141 if ((status->position == 1) && (status->of_total == 100))
1144 if (status->of_total > 0)
1145 priv->done += status->position/status->of_total;
1147 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1153 modest_mail_operation_remove_msg (ModestMailOperation *self,
1155 gboolean remove_to_trash)
1158 ModestMailOperationPrivate *priv;
1160 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1161 g_return_if_fail (TNY_IS_HEADER (header));
1163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1164 folder = tny_header_get_folder (header);
1166 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1168 /* Delete or move to trash */
1169 if (remove_to_trash) {
1170 TnyFolder *trash_folder;
1171 TnyStoreAccount *store_account;
1173 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1174 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1175 TNY_FOLDER_TYPE_TRASH);
1180 headers = tny_simple_list_new ();
1181 tny_list_append (headers, G_OBJECT (header));
1182 g_object_unref (header);
1185 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1186 g_object_unref (headers);
1187 /* g_object_unref (trash_folder); */
1189 ModestMailOperationPrivate *priv;
1191 /* Set status failed and set an error */
1192 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1193 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1194 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1195 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1196 _("Error trying to delete a message. Trash folder not found"));
1199 g_object_unref (G_OBJECT (store_account));
1201 tny_folder_remove_msg (folder, header, &(priv->error));
1203 tny_folder_sync(folder, TRUE, &(priv->error));
1208 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1210 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1213 g_object_unref (G_OBJECT (folder));
1215 /* Notify the queue */
1216 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1220 transfer_msgs_status_cb (GObject *obj,
1224 XFerMsgAsyncHelper *helper = NULL;
1225 ModestMailOperation *self;
1226 ModestMailOperationPrivate *priv;
1228 g_return_if_fail (status != NULL);
1229 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1231 helper = (XFerMsgAsyncHelper *) user_data;
1232 g_return_if_fail (helper != NULL);
1234 /* Temporary FIX: useful when tinymail send us status
1235 information *after* calling the function callback */
1236 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1239 self = helper->mail_op;
1240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1242 if ((status->position == 1) && (status->of_total == 100))
1245 priv->done = status->position;
1246 priv->total = status->of_total;
1248 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1253 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1255 XFerMsgAsyncHelper *helper;
1256 ModestMailOperation *self;
1257 ModestMailOperationPrivate *priv;
1259 helper = (XFerMsgAsyncHelper *) user_data;
1260 self = helper->mail_op;
1262 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1265 priv->error = g_error_copy (*err);
1267 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1268 } else if (cancelled) {
1269 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1270 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1271 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1272 _("Error trying to refresh the contents of %s"),
1273 tny_folder_get_name (folder));
1276 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1280 /* g_object_unref (helper->headers); */
1281 /* g_object_unref (helper->dest_folder); */
1282 /* g_object_unref (helper->mail_op); */
1283 g_slice_free (XFerMsgAsyncHelper, helper);
1284 g_object_unref (folder);
1286 /* Notify the queue */
1287 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1291 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1294 gboolean delete_original)
1296 ModestMailOperationPrivate *priv;
1298 TnyFolder *src_folder;
1299 XFerMsgAsyncHelper *helper;
1302 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1303 g_return_if_fail (TNY_IS_LIST (headers));
1304 g_return_if_fail (TNY_IS_FOLDER (folder));
1306 /* Pick references for async calls */
1307 g_object_ref (folder);
1309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1312 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1314 /* Create the helper */
1315 helper = g_slice_new0 (XFerMsgAsyncHelper);
1316 helper->mail_op = self;
1317 helper->dest_folder = g_object_ref(folder);
1318 helper->headers = g_object_ref(headers);
1320 /* Get source folder */
1321 iter = tny_list_create_iterator (headers);
1322 header = TNY_HEADER (tny_iterator_get_current (iter));
1323 src_folder = tny_header_get_folder (header);
1324 g_object_unref (header);
1325 g_object_unref (iter);
1327 /* Transfer messages */
1328 tny_folder_transfer_msgs_async (src_folder,
1333 transfer_msgs_status_cb,
1339 on_refresh_folder (TnyFolder *folder,
1344 ModestMailOperation *self;
1345 ModestMailOperationPrivate *priv;
1347 self = MODEST_MAIL_OPERATION (user_data);
1348 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1351 priv->error = g_error_copy (*error);
1352 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1357 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1358 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1359 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1360 _("Error trying to refresh the contents of %s"),
1361 tny_folder_get_name (folder));
1365 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1369 g_object_unref (folder);
1371 /* Notify the queue */
1372 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1376 on_refresh_folder_status_update (GObject *obj,
1380 ModestMailOperation *self;
1381 ModestMailOperationPrivate *priv;
1383 g_return_if_fail (status != NULL);
1384 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1386 /* Temporary FIX: useful when tinymail send us status
1387 information *after* calling the function callback */
1388 if (!MODEST_IS_MAIL_OPERATION (user_data))
1391 self = MODEST_MAIL_OPERATION (user_data);
1392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1394 priv->done = status->position;
1395 priv->total = status->of_total;
1397 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1401 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1404 ModestMailOperationPrivate *priv;
1406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1408 /* Pick a reference */
1409 g_object_ref (folder);
1411 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1413 /* Refresh the folder. TODO: tinymail could issue a status
1414 updates before the callback call then this could happen. We
1415 must review the design */
1416 tny_folder_refresh_async (folder,
1418 on_refresh_folder_status_update,
1423 _modest_mail_operation_notify_end (ModestMailOperation *self)
1425 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);