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;
398 TnyTransportAccount *transport_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;
462 ModestTnySendQueue *send_queue;
465 info = (UpdateAccountInfo *) thr_user_data;
466 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
468 /* Get all the folders We can do it synchronously because
469 we're already running in a different thread than the UI */
470 all_folders = tny_simple_list_new ();
471 query = tny_folder_store_query_new ();
472 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
473 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
478 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
482 iter = tny_list_create_iterator (all_folders);
483 while (!tny_iterator_is_done (iter)) {
484 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
486 recurse_folders (folder, query, all_folders);
487 tny_iterator_next (iter);
489 g_object_unref (G_OBJECT (iter));
491 /* Update status and notify. We need to call the notification
492 with a source functopm in order to call it from the main
493 loop. We need that in order not to get into trouble with
494 Gtk+. We use a timeout in order to provide more status
495 information, because the sync tinymail call does not
496 provide it for the moment */
497 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
499 /* Refresh folders */
500 iter = tny_list_create_iterator (all_folders);
501 while (!tny_iterator_is_done (iter) && !priv->error) {
503 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
505 /* Refresh the folder */
506 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
509 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
512 g_object_unref (G_OBJECT (folder));
513 tny_iterator_next (iter);
515 g_object_unref (G_OBJECT (iter));
516 g_source_remove (timeout);
519 priv->id = MODEST_MAIL_OPERATION_ID_SEND;
521 send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
523 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
524 modest_tny_send_queue_flush (send_queue);
525 g_source_remove (timeout);
527 g_object_unref (G_OBJECT(send_queue));
529 /* Check if the operation was a success */
531 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
533 /* Update the last updated key */
534 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
535 tny_account_get_id (TNY_ACCOUNT (info->account)),
536 MODEST_ACCOUNT_LAST_UPDATED,
542 /* Notify the queue */
543 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
546 g_object_unref (query);
547 g_object_unref (all_folders);
548 g_object_unref (info->mail_op);
549 g_object_unref (info->account);
550 g_object_unref (info->transport_account);
551 g_slice_free (UpdateAccountInfo, info);
557 modest_mail_operation_update_account (ModestMailOperation *self,
558 const gchar *account_name)
561 UpdateAccountInfo *info;
562 ModestMailOperationPrivate *priv;
563 TnyStoreAccount *modest_account;
564 TnyTransportAccount *transport_account;
565 gchar *modest_acc_name;
567 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
568 g_return_val_if_fail (account_name, FALSE);
570 /* Init mail operation. Set total and done to 0, and do not
571 update them, this way the progress objects will know that
572 we have no clue about the number of the objects */
573 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
576 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
578 /* Get the Modest account */
579 modest_account = (TnyStoreAccount *)
580 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
582 TNY_ACCOUNT_TYPE_STORE);
584 if (!modest_account) {
585 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
586 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
587 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
588 "cannot get tny store account for %s\n", account_name);
589 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
594 /* Get the transport account, we can not do it in the thread
595 due to some problems with dbus */
596 modest_acc_name = (gchar *) g_object_get_data (G_OBJECT (modest_account), "modest_account");
597 transport_account = (TnyTransportAccount *)
598 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
600 if (!transport_account) {
601 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
603 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
604 "cannot get tny transport account for %s\n", modest_acc_name);
605 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
610 /* Create the helper object */
611 info = g_slice_new (UpdateAccountInfo);
612 info->mail_op = g_object_ref (self);
613 info->account = modest_account;
614 info->transport_account = transport_account;
616 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
621 ModestMailOperationStatus
622 modest_mail_operation_get_status (ModestMailOperation *self)
624 ModestMailOperationPrivate *priv;
626 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
627 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
628 MODEST_MAIL_OPERATION_STATUS_INVALID);
630 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
635 modest_mail_operation_get_error (ModestMailOperation *self)
637 ModestMailOperationPrivate *priv;
639 g_return_val_if_fail (self, NULL);
640 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
642 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
647 modest_mail_operation_cancel (ModestMailOperation *self)
649 ModestMailOperationPrivate *priv;
651 if (!MODEST_IS_MAIL_OPERATION (self)) {
652 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
656 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
658 /* TODO: Tinymail does not support cancel operation */
661 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
663 /* Notify the queue */
664 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
670 modest_mail_operation_get_task_done (ModestMailOperation *self)
672 ModestMailOperationPrivate *priv;
674 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
681 modest_mail_operation_get_task_total (ModestMailOperation *self)
683 ModestMailOperationPrivate *priv;
685 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
687 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
692 modest_mail_operation_is_finished (ModestMailOperation *self)
694 ModestMailOperationPrivate *priv;
695 gboolean retval = FALSE;
697 if (!MODEST_IS_MAIL_OPERATION (self)) {
698 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
702 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
704 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
705 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
706 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
707 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
716 /* ******************************************************************* */
717 /* ************************** STORE ACTIONS ************************* */
718 /* ******************************************************************* */
722 modest_mail_operation_create_folder (ModestMailOperation *self,
723 TnyFolderStore *parent,
726 ModestTnyFolderRules rules;
727 ModestMailOperationPrivate *priv;
728 TnyFolder *new_folder = NULL;
729 gboolean can_create = FALSE;
731 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
732 g_return_val_if_fail (name, NULL);
734 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
737 if (!TNY_IS_FOLDER (parent)) {
738 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
739 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
740 _("mail_in_ui_folder_create_error"));
742 /* Check folder rules */
743 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
744 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
746 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
747 _("mail_in_ui_folder_create_error"));
753 /* Create the folder */
754 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
755 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
758 /* Notify the queue */
759 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
765 modest_mail_operation_remove_folder (ModestMailOperation *self,
767 gboolean remove_to_trash)
770 ModestMailOperationPrivate *priv;
771 ModestTnyFolderRules rules;
773 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
774 g_return_if_fail (TNY_IS_FOLDER (folder));
776 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
778 /* Check folder rules */
779 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
780 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
781 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
782 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
783 _("mail_in_ui_folder_delete_error"));
787 /* Get the account */
788 account = tny_folder_get_account (folder);
790 /* Delete folder or move to trash */
791 if (remove_to_trash) {
792 TnyFolder *trash_folder = NULL;
793 /* TnyFolder *trash_folder, *new_folder; */
794 trash_folder = modest_tny_account_get_special_folder (account,
795 TNY_FOLDER_TYPE_TRASH);
796 /* TODO: error_handling */
797 modest_mail_operation_xfer_folder (self, folder,
798 TNY_FOLDER_STORE (trash_folder), TRUE);
799 /* new_folder = modest_mail_operation_xfer_folder (self, folder, */
800 /* TNY_FOLDER_STORE (trash_folder), TRUE); */
801 /* g_object_unref (G_OBJECT (new_folder)); */
803 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
805 tny_folder_store_remove_folder (parent, folder, &(priv->error));
806 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
809 g_object_unref (G_OBJECT (parent));
811 g_object_unref (G_OBJECT (account));
814 /* Notify the queue */
815 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
819 modest_mail_operation_rename_folder (ModestMailOperation *self,
823 ModestMailOperationPrivate *priv;
824 ModestTnyFolderRules rules;
826 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
827 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
828 g_return_if_fail (name);
830 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
832 /* Check folder rules */
833 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
834 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
835 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
836 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
837 _("FIXME: unable to rename"));
839 /* Rename. Camel handles folder subscription/unsubscription */
840 tny_folder_set_name (folder, name, &(priv->error));
841 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
844 /* Notify the queue */
845 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
849 transfer_folder_status_cb (GObject *obj,
853 XFerMsgAsyncHelper *helper = NULL;
854 ModestMailOperation *self;
855 ModestMailOperationPrivate *priv;
857 g_return_if_fail (status != NULL);
858 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
860 helper = (XFerMsgAsyncHelper *) user_data;
861 g_return_if_fail (helper != NULL);
863 /* Temporary FIX: useful when tinymail send us status
864 information *after* calling the function callback */
865 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
868 self = helper->mail_op;
869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
871 if ((status->position == 1) && (status->of_total == 100))
874 priv->done = status->position;
875 priv->total = status->of_total;
878 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
883 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
885 XFerFolderAsyncHelper *helper = NULL;
886 ModestMailOperation *self = NULL;
887 ModestMailOperationPrivate *priv = NULL;
889 helper = (XFerFolderAsyncHelper *) user_data;
890 self = helper->mail_op;
892 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
895 priv->error = g_error_copy (*err);
897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
898 } else if (cancelled) {
899 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
900 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
901 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
902 _("Error trying to refresh the contents of %s"),
903 tny_folder_get_name (folder));
906 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
910 g_slice_free (XFerFolderAsyncHelper, helper);
911 g_object_unref (folder);
912 g_object_unref (into);
913 g_object_unref (new_folder);
915 /* Notify the queue */
916 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
920 modest_mail_operation_xfer_folder (ModestMailOperation *self,
922 TnyFolderStore *parent,
923 gboolean delete_original)
925 ModestMailOperationPrivate *priv;
926 TnyFolder *new_folder = NULL;
927 ModestTnyFolderRules rules;
929 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
930 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
931 g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
935 /* The moveable restriction is applied also to copy operation */
936 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
937 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
938 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
939 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
940 _("FIXME: unable to rename"));
942 /* Move/Copy folder */
943 new_folder = tny_folder_copy (folder,
945 tny_folder_get_name (folder),
950 /* Notify the queue */
951 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
957 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
959 TnyFolderStore *parent,
960 gboolean delete_original)
962 XFerFolderAsyncHelper *helper = NULL;
963 ModestMailOperationPrivate *priv = NULL;
964 ModestTnyFolderRules rules;
966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
967 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
968 g_return_if_fail (TNY_IS_FOLDER (folder));
970 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
972 /* The moveable restriction is applied also to copy operation */
973 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
974 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
975 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
976 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
977 _("FIXME: unable to rename"));
979 helper = g_slice_new0 (XFerFolderAsyncHelper);
980 helper->mail_op = self;
982 /* Move/Copy folder */
983 tny_folder_copy_async (folder,
985 tny_folder_get_name (folder),
988 transfer_folder_status_cb,
994 /* ******************************************************************* */
995 /* ************************** MSG ACTIONS ************************* */
996 /* ******************************************************************* */
998 void modest_mail_operation_get_msg (ModestMailOperation *self,
1000 GetMsgAsynUserCallback user_callback,
1003 GetMsgAsyncHelper *helper = NULL;
1005 ModestMailOperationPrivate *priv;
1007 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1008 g_return_if_fail (TNY_IS_HEADER (header));
1010 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1011 folder = tny_header_get_folder (header);
1013 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1015 /* Get message from folder */
1017 helper = g_slice_new0 (GetMsgAsyncHelper);
1018 helper->mail_op = self;
1019 helper->user_callback = user_callback;
1020 helper->pending_ops = 1;
1021 helper->user_data = user_data;
1023 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1025 g_object_unref (G_OBJECT (folder));
1027 /* Set status failed and set an error */
1028 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1029 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1030 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1031 _("Error trying to get a message. No folder found for header"));
1036 get_msg_cb (TnyFolder *folder,
1042 GetMsgAsyncHelper *helper = NULL;
1043 ModestMailOperation *self = NULL;
1044 ModestMailOperationPrivate *priv = NULL;
1046 helper = (GetMsgAsyncHelper *) user_data;
1047 g_return_if_fail (helper != NULL);
1048 self = helper->mail_op;
1049 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1050 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1052 helper->pending_ops--;
1054 /* Check errors and cancel */
1056 priv->error = g_error_copy (*error);
1057 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1062 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1063 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1064 _("Error trying to refresh the contents of %s"),
1065 tny_folder_get_name (folder));
1069 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1071 /* If user defined callback function was defined, call it */
1072 if (helper->user_callback) {
1073 helper->user_callback (priv->source, msg, helper->user_data);
1078 if (helper->pending_ops == 0) {
1079 g_slice_free (GetMsgAsyncHelper, helper);
1081 /* Notify the queue */
1082 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1087 get_msg_status_cb (GObject *obj,
1091 GetMsgAsyncHelper *helper = NULL;
1092 ModestMailOperation *self;
1093 ModestMailOperationPrivate *priv;
1095 g_return_if_fail (status != NULL);
1096 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1098 helper = (GetMsgAsyncHelper *) user_data;
1099 g_return_if_fail (helper != NULL);
1101 /* Temporary FIX: useful when tinymail send us status
1102 information *after* calling the function callback */
1103 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1106 self = helper->mail_op;
1107 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1109 if ((status->position == 1) && (status->of_total == 100))
1115 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1119 void modest_mail_operation_process_msg (ModestMailOperation *self,
1120 TnyList *header_list,
1121 GetMsgAsynUserCallback user_callback,
1124 ModestMailOperationPrivate *priv = NULL;
1125 GetMsgAsyncHelper *helper = NULL;
1126 TnyHeader *header = NULL;
1127 TnyFolder *folder = NULL;
1128 TnyIterator *iter = NULL;
1130 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1132 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1133 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1135 iter = tny_list_create_iterator (header_list);
1137 priv->total = tny_list_get_length(header_list);
1139 helper = g_slice_new0 (GetMsgAsyncHelper);
1140 helper->mail_op = self;
1141 helper->user_callback = user_callback;
1142 helper->pending_ops = priv->total;
1143 helper->user_data = user_data;
1145 while (!tny_iterator_is_done (iter)) {
1147 header = TNY_HEADER (tny_iterator_get_current (iter));
1148 folder = tny_header_get_folder (header);
1150 /* Get message from folder */
1152 /* The callback will call it per each header */
1153 tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1154 g_object_unref (G_OBJECT (folder));
1156 /* Set status failed and set an error */
1157 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1158 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1159 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1160 _("Error trying to get a message. No folder found for header"));
1162 /* Notify the queue */
1163 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1166 g_slice_free (GetMsgAsyncHelper, helper);
1170 g_object_unref (header);
1171 tny_iterator_next (iter);
1176 update_process_msg_status_cb (GObject *obj,
1180 GetMsgAsyncHelper *helper = NULL;
1181 ModestMailOperation *self;
1182 ModestMailOperationPrivate *priv;
1184 g_return_if_fail (status != NULL);
1185 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1187 helper = (GetMsgAsyncHelper *) user_data;
1188 g_return_if_fail (helper != NULL);
1190 /* Temporary FIX: useful when tinymail send us status
1191 information *after* calling the function callback */
1192 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1195 self = helper->mail_op;
1196 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1198 if ((status->position == 1) && (status->of_total == 100))
1201 if (status->of_total > 0)
1202 priv->done += status->position/status->of_total;
1204 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1210 modest_mail_operation_remove_msg (ModestMailOperation *self,
1212 gboolean remove_to_trash)
1215 ModestMailOperationPrivate *priv;
1217 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1218 g_return_if_fail (TNY_IS_HEADER (header));
1220 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1221 folder = tny_header_get_folder (header);
1223 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1225 /* Delete or move to trash */
1226 if (remove_to_trash) {
1227 TnyFolder *trash_folder;
1228 TnyStoreAccount *store_account;
1230 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1231 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1232 TNY_FOLDER_TYPE_TRASH);
1237 headers = tny_simple_list_new ();
1238 tny_list_append (headers, G_OBJECT (header));
1239 g_object_unref (header);
1242 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1243 g_object_unref (headers);
1244 /* g_object_unref (trash_folder); */
1246 ModestMailOperationPrivate *priv;
1248 /* Set status failed and set an error */
1249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1251 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1252 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1253 _("Error trying to delete a message. Trash folder not found"));
1256 g_object_unref (G_OBJECT (store_account));
1258 tny_folder_remove_msg (folder, header, &(priv->error));
1260 tny_folder_sync(folder, TRUE, &(priv->error));
1265 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1267 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1270 g_object_unref (G_OBJECT (folder));
1272 /* Notify the queue */
1273 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1277 transfer_msgs_status_cb (GObject *obj,
1281 XFerMsgAsyncHelper *helper = NULL;
1282 ModestMailOperation *self;
1283 ModestMailOperationPrivate *priv;
1285 g_return_if_fail (status != NULL);
1286 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1288 helper = (XFerMsgAsyncHelper *) user_data;
1289 g_return_if_fail (helper != NULL);
1291 /* Temporary FIX: useful when tinymail send us status
1292 information *after* calling the function callback */
1293 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1296 self = helper->mail_op;
1297 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1299 if ((status->position == 1) && (status->of_total == 100))
1302 priv->done = status->position;
1303 priv->total = status->of_total;
1305 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1310 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1312 XFerMsgAsyncHelper *helper;
1313 ModestMailOperation *self;
1314 ModestMailOperationPrivate *priv;
1316 helper = (XFerMsgAsyncHelper *) user_data;
1317 self = helper->mail_op;
1319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1322 priv->error = g_error_copy (*err);
1324 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1325 } else if (cancelled) {
1326 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1327 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1328 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1329 _("Error trying to refresh the contents of %s"),
1330 tny_folder_get_name (folder));
1333 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1337 /* g_object_unref (helper->headers); */
1338 /* g_object_unref (helper->dest_folder); */
1339 /* g_object_unref (helper->mail_op); */
1340 g_slice_free (XFerMsgAsyncHelper, helper);
1341 g_object_unref (folder);
1343 /* Notify the queue */
1344 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1348 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1351 gboolean delete_original)
1353 ModestMailOperationPrivate *priv;
1355 TnyFolder *src_folder;
1356 XFerMsgAsyncHelper *helper;
1359 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1360 g_return_if_fail (TNY_IS_LIST (headers));
1361 g_return_if_fail (TNY_IS_FOLDER (folder));
1363 /* Pick references for async calls */
1364 g_object_ref (folder);
1366 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1369 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1371 /* Create the helper */
1372 helper = g_slice_new0 (XFerMsgAsyncHelper);
1373 helper->mail_op = self;
1374 helper->dest_folder = g_object_ref(folder);
1375 helper->headers = g_object_ref(headers);
1377 /* Get source folder */
1378 iter = tny_list_create_iterator (headers);
1379 header = TNY_HEADER (tny_iterator_get_current (iter));
1380 src_folder = tny_header_get_folder (header);
1381 g_object_unref (header);
1382 g_object_unref (iter);
1384 /* Transfer messages */
1385 tny_folder_transfer_msgs_async (src_folder,
1390 transfer_msgs_status_cb,
1396 on_refresh_folder (TnyFolder *folder,
1401 ModestMailOperation *self;
1402 ModestMailOperationPrivate *priv;
1404 self = MODEST_MAIL_OPERATION (user_data);
1405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1408 priv->error = g_error_copy (*error);
1409 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1415 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1416 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1417 _("Error trying to refresh the contents of %s"),
1418 tny_folder_get_name (folder));
1422 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1426 g_object_unref (folder);
1428 /* Notify the queue */
1429 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1433 on_refresh_folder_status_update (GObject *obj,
1437 ModestMailOperation *self;
1438 ModestMailOperationPrivate *priv;
1440 g_return_if_fail (status != NULL);
1441 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1443 /* Temporary FIX: useful when tinymail send us status
1444 information *after* calling the function callback */
1445 if (!MODEST_IS_MAIL_OPERATION (user_data))
1448 self = MODEST_MAIL_OPERATION (user_data);
1449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1451 priv->done = status->position;
1452 priv->total = status->of_total;
1454 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1458 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1461 ModestMailOperationPrivate *priv;
1463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1465 /* Pick a reference */
1466 g_object_ref (folder);
1468 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1470 /* Refresh the folder. TODO: tinymail could issue a status
1471 updates before the callback call then this could happen. We
1472 must review the design */
1473 tny_folder_refresh_async (folder,
1475 on_refresh_folder_status_update,
1480 _modest_mail_operation_notify_end (ModestMailOperation *self)
1482 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);