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;
119 XferMsgsAsynUserCallback user_callback;
121 } XFerMsgAsyncHelper;
123 typedef struct _XFerFolderAsyncHelper
125 ModestMailOperation *mail_op;
127 } XFerFolderAsyncHelper;
131 static GObjectClass *parent_class = NULL;
133 static guint signals[NUM_SIGNALS] = {0};
136 modest_mail_operation_get_type (void)
138 static GType my_type = 0;
140 static const GTypeInfo my_info = {
141 sizeof(ModestMailOperationClass),
142 NULL, /* base init */
143 NULL, /* base finalize */
144 (GClassInitFunc) modest_mail_operation_class_init,
145 NULL, /* class finalize */
146 NULL, /* class data */
147 sizeof(ModestMailOperation),
149 (GInstanceInitFunc) modest_mail_operation_init,
152 my_type = g_type_register_static (G_TYPE_OBJECT,
153 "ModestMailOperation",
160 modest_mail_operation_class_init (ModestMailOperationClass *klass)
162 GObjectClass *gobject_class;
163 gobject_class = (GObjectClass*) klass;
165 parent_class = g_type_class_peek_parent (klass);
166 gobject_class->finalize = modest_mail_operation_finalize;
168 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
171 * ModestMailOperation::progress-changed
172 * @self: the #MailOperation that emits the signal
173 * @user_data: user data set when the signal handler was connected
175 * Emitted when the progress of a mail operation changes
177 signals[PROGRESS_CHANGED_SIGNAL] =
178 g_signal_new ("progress-changed",
179 G_TYPE_FROM_CLASS (gobject_class),
181 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
183 g_cclosure_marshal_VOID__VOID,
188 modest_mail_operation_init (ModestMailOperation *obj)
190 ModestMailOperationPrivate *priv;
192 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
194 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
195 priv->id = MODEST_MAIL_OPERATION_ID_UNKNOWN;
203 modest_mail_operation_finalize (GObject *obj)
205 ModestMailOperationPrivate *priv;
207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
210 g_error_free (priv->error);
214 g_object_unref (priv->source);
218 G_OBJECT_CLASS(parent_class)->finalize (obj);
222 modest_mail_operation_new (ModestMailOperationId id,
225 ModestMailOperation *obj;
226 ModestMailOperationPrivate *priv;
228 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
229 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
233 priv->source = g_object_ref(source);
239 ModestMailOperationId
240 modest_mail_operation_get_id (ModestMailOperation *self)
242 ModestMailOperationPrivate *priv;
244 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
250 modest_mail_operation_is_mine (ModestMailOperation *self,
253 ModestMailOperationPrivate *priv;
255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
256 if (priv->source == NULL) return FALSE;
258 return priv->source == me;
263 modest_mail_operation_send_mail (ModestMailOperation *self,
264 TnyTransportAccount *transport_account,
267 TnySendQueue *send_queue;
269 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
270 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
271 g_return_if_fail (TNY_IS_MSG (msg));
273 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
274 if (!TNY_IS_SEND_QUEUE(send_queue))
275 g_printerr ("modest: could not find send queue for account\n");
278 tny_send_queue_add (send_queue, msg, &err);
280 g_printerr ("modest: error adding msg to send queue: %s\n",
284 /* g_message ("modest: message added to send queue"); */
288 /* Notify the queue */
289 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
293 modest_mail_operation_send_new_mail (ModestMailOperation *self,
294 TnyTransportAccount *transport_account,
295 const gchar *from, const gchar *to,
296 const gchar *cc, const gchar *bcc,
297 const gchar *subject, const gchar *plain_body,
298 const gchar *html_body,
299 const GList *attachments_list,
300 TnyHeaderFlags priority_flags)
303 ModestMailOperationPrivate *priv = NULL;
304 /* GList *node = NULL; */
306 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
307 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
311 /* Check parametters */
313 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
314 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
315 _("Error trying to send a mail. You need to set at least one recipient"));
319 if (html_body == NULL) {
320 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
322 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
325 g_printerr ("modest: failed to create a new msg\n");
329 /* TODO: add priority handling. It's received in the priority_flags operator, and
330 it should have effect in the sending operation */
332 /* Call mail operation */
333 modest_mail_operation_send_mail (self, transport_account, new_msg);
336 g_object_unref (G_OBJECT (new_msg));
340 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
341 TnyTransportAccount *transport_account,
342 const gchar *from, const gchar *to,
343 const gchar *cc, const gchar *bcc,
344 const gchar *subject, const gchar *plain_body,
345 const gchar *html_body,
346 const GList *attachments_list,
347 TnyHeaderFlags priority_flags)
350 TnyFolder *folder = NULL;
351 ModestMailOperationPrivate *priv = NULL;
354 /* GList *node = NULL; */
356 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
357 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
361 if (html_body == NULL) {
362 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
364 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
367 g_printerr ("modest: failed to create a new msg\n");
371 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
373 g_printerr ("modest: failed to find Drafts folder\n");
377 tny_folder_add_msg (folder, msg, &err);
379 g_printerr ("modest: error adding msg to Drafts folder: %s",
385 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
390 g_object_unref (G_OBJECT(msg));
392 g_object_unref (G_OBJECT(folder));
397 ModestMailOperation *mail_op;
398 TnyStoreAccount *account;
399 TnyTransportAccount *transport_account;
403 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
406 TnyList *folders = tny_simple_list_new ();
408 tny_folder_store_get_folders (store, folders, query, NULL);
409 iter = tny_list_create_iterator (folders);
411 while (!tny_iterator_is_done (iter)) {
413 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
415 tny_list_prepend (all_folders, G_OBJECT (folder));
416 recurse_folders (folder, query, all_folders);
417 g_object_unref (G_OBJECT (folder));
419 tny_iterator_next (iter);
421 g_object_unref (G_OBJECT (iter));
422 g_object_unref (G_OBJECT (folders));
426 * Used by update_account_thread to emit the signal from the main
427 * loop. We call it inside an idle call to achieve that
430 notify_update_account_observers (gpointer data)
432 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
434 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
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;
463 ModestTnySendQueue *send_queue;
466 info = (UpdateAccountInfo *) thr_user_data;
467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
469 /* Get all the folders We can do it synchronously because
470 we're already running in a different thread than the UI */
471 all_folders = tny_simple_list_new ();
472 query = tny_folder_store_query_new ();
473 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
474 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
479 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
483 iter = tny_list_create_iterator (all_folders);
484 while (!tny_iterator_is_done (iter)) {
485 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
487 recurse_folders (folder, query, all_folders);
488 tny_iterator_next (iter);
490 g_object_unref (G_OBJECT (iter));
492 /* Update status and notify. We need to call the notification
493 with a source functopm in order to call it from the main
494 loop. We need that in order not to get into trouble with
495 Gtk+. We use a timeout in order to provide more status
496 information, because the sync tinymail call does not
497 provide it for the moment */
498 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
500 /* Refresh folders */
501 iter = tny_list_create_iterator (all_folders);
502 while (!tny_iterator_is_done (iter) && !priv->error) {
504 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
506 /* Refresh the folder */
507 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
510 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
513 g_object_unref (G_OBJECT (folder));
514 tny_iterator_next (iter);
516 g_object_unref (G_OBJECT (iter));
517 g_source_remove (timeout);
520 priv->id = MODEST_MAIL_OPERATION_ID_SEND;
522 send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
524 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
525 modest_tny_send_queue_flush (send_queue);
526 g_source_remove (timeout);
528 g_object_unref (G_OBJECT(send_queue));
530 /* Check if the operation was a success */
532 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
534 /* Update the last updated key */
535 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
536 tny_account_get_id (TNY_ACCOUNT (info->account)),
537 MODEST_ACCOUNT_LAST_UPDATED,
543 /* Notify the queue */
544 g_idle_add (notify_update_account_queue, g_object_ref (info->mail_op));
547 g_object_unref (query);
548 g_object_unref (all_folders);
549 g_object_unref (info->mail_op);
550 g_object_unref (info->account);
551 g_object_unref (info->transport_account);
552 g_slice_free (UpdateAccountInfo, info);
558 modest_mail_operation_update_account (ModestMailOperation *self,
559 const gchar *account_name)
562 UpdateAccountInfo *info;
563 ModestMailOperationPrivate *priv;
564 TnyStoreAccount *modest_account;
565 TnyTransportAccount *transport_account;
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 transport_account = (TnyTransportAccount *)
597 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
599 if (!transport_account) {
600 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
601 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
602 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
603 "cannot get tny transport account for %s\n", account_name);
604 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
609 /* Create the helper object */
610 info = g_slice_new (UpdateAccountInfo);
611 info->mail_op = g_object_ref (self);
612 info->account = modest_account;
613 info->transport_account = transport_account;
615 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
620 ModestMailOperationStatus
621 modest_mail_operation_get_status (ModestMailOperation *self)
623 ModestMailOperationPrivate *priv;
625 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
626 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
627 MODEST_MAIL_OPERATION_STATUS_INVALID);
629 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
634 modest_mail_operation_get_error (ModestMailOperation *self)
636 ModestMailOperationPrivate *priv;
638 g_return_val_if_fail (self, NULL);
639 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
641 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
646 modest_mail_operation_cancel (ModestMailOperation *self)
648 ModestMailOperationPrivate *priv;
650 if (!MODEST_IS_MAIL_OPERATION (self)) {
651 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
655 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
657 /* TODO: Tinymail does not support cancel operation */
660 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
662 /* Notify the queue */
663 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
669 modest_mail_operation_get_task_done (ModestMailOperation *self)
671 ModestMailOperationPrivate *priv;
673 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
675 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
680 modest_mail_operation_get_task_total (ModestMailOperation *self)
682 ModestMailOperationPrivate *priv;
684 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
686 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
691 modest_mail_operation_is_finished (ModestMailOperation *self)
693 ModestMailOperationPrivate *priv;
694 gboolean retval = FALSE;
696 if (!MODEST_IS_MAIL_OPERATION (self)) {
697 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
701 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
703 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
704 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
705 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
706 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
715 /* ******************************************************************* */
716 /* ************************** STORE ACTIONS ************************* */
717 /* ******************************************************************* */
721 modest_mail_operation_create_folder (ModestMailOperation *self,
722 TnyFolderStore *parent,
725 ModestTnyFolderRules rules;
726 ModestMailOperationPrivate *priv;
727 TnyFolder *new_folder = NULL;
728 gboolean can_create = FALSE;
730 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
731 g_return_val_if_fail (name, NULL);
733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
736 if (!TNY_IS_FOLDER (parent)) {
737 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
738 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
739 _("mail_in_ui_folder_create_error"));
741 /* Check folder rules */
742 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
743 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
744 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
745 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
746 _("mail_in_ui_folder_create_error"));
752 /* Create the folder */
753 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
754 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
757 /* Notify the queue */
758 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
764 modest_mail_operation_remove_folder (ModestMailOperation *self,
766 gboolean remove_to_trash)
769 ModestMailOperationPrivate *priv;
770 ModestTnyFolderRules rules;
772 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
773 g_return_if_fail (TNY_IS_FOLDER (folder));
775 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
777 /* Check folder rules */
778 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
779 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
780 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
781 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
782 _("mail_in_ui_folder_delete_error"));
786 /* Get the account */
787 account = tny_folder_get_account (folder);
789 /* Delete folder or move to trash */
790 if (remove_to_trash) {
791 TnyFolder *trash_folder = NULL;
792 /* TnyFolder *trash_folder, *new_folder; */
793 trash_folder = modest_tny_account_get_special_folder (account,
794 TNY_FOLDER_TYPE_TRASH);
795 /* TODO: error_handling */
796 modest_mail_operation_xfer_folder (self, folder,
797 TNY_FOLDER_STORE (trash_folder), TRUE);
798 /* new_folder = modest_mail_operation_xfer_folder (self, folder, */
799 /* TNY_FOLDER_STORE (trash_folder), TRUE); */
800 /* g_object_unref (G_OBJECT (new_folder)); */
802 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
804 tny_folder_store_remove_folder (parent, folder, &(priv->error));
805 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
808 g_object_unref (G_OBJECT (parent));
810 g_object_unref (G_OBJECT (account));
813 /* Notify the queue */
814 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
818 modest_mail_operation_rename_folder (ModestMailOperation *self,
822 ModestMailOperationPrivate *priv;
823 ModestTnyFolderRules rules;
825 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
826 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
827 g_return_if_fail (name);
829 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
831 /* Check folder rules */
832 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
833 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
834 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
835 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
836 _("FIXME: unable to rename"));
838 /* Rename. Camel handles folder subscription/unsubscription */
840 TnyFolderStore *into;
843 into = tny_folder_get_folder_store (folder);
844 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
846 g_object_unref (into);
848 g_object_unref (nfol);
850 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
853 /* Notify the queue */
854 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
858 transfer_folder_status_cb (GObject *obj,
862 XFerMsgAsyncHelper *helper = NULL;
863 ModestMailOperation *self;
864 ModestMailOperationPrivate *priv;
866 g_return_if_fail (status != NULL);
867 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
869 helper = (XFerMsgAsyncHelper *) user_data;
870 g_return_if_fail (helper != NULL);
872 /* Temporary FIX: useful when tinymail send us status
873 information *after* calling the function callback */
874 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
877 self = helper->mail_op;
878 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
880 if ((status->position == 1) && (status->of_total == 100))
883 priv->done = status->position;
884 priv->total = status->of_total;
887 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
892 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
894 XFerFolderAsyncHelper *helper = NULL;
895 ModestMailOperation *self = NULL;
896 ModestMailOperationPrivate *priv = NULL;
898 helper = (XFerFolderAsyncHelper *) user_data;
899 self = helper->mail_op;
901 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
904 priv->error = g_error_copy (*err);
906 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
907 } else if (cancelled) {
908 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
909 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
910 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
911 _("Error trying to refresh the contents of %s"),
912 tny_folder_get_name (folder));
915 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
919 g_slice_free (XFerFolderAsyncHelper, helper);
920 g_object_unref (folder);
921 g_object_unref (into);
922 g_object_unref (new_folder);
924 /* Notify the queue */
925 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
929 modest_mail_operation_xfer_folder (ModestMailOperation *self,
931 TnyFolderStore *parent,
932 gboolean delete_original)
934 ModestMailOperationPrivate *priv;
935 TnyFolder *new_folder = NULL;
936 ModestTnyFolderRules rules;
938 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
939 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
940 g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
942 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
944 /* The moveable restriction is applied also to copy operation */
945 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
946 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
947 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
948 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
949 _("FIXME: unable to rename"));
951 /* Move/Copy folder */
952 new_folder = tny_folder_copy (folder,
954 tny_folder_get_name (folder),
959 /* Notify the queue */
960 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
966 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
968 TnyFolderStore *parent,
969 gboolean delete_original)
971 XFerFolderAsyncHelper *helper = NULL;
972 ModestMailOperationPrivate *priv = NULL;
973 ModestTnyFolderRules rules;
975 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
976 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
977 g_return_if_fail (TNY_IS_FOLDER (folder));
979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
981 /* Pick references for async calls */
982 g_object_ref (folder);
983 g_object_ref (parent);
985 /* The moveable restriction is applied also to copy operation */
986 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
987 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
988 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
989 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
990 _("FIXME: unable to rename"));
992 helper = g_slice_new0 (XFerFolderAsyncHelper);
993 helper->mail_op = self;
995 /* Move/Copy folder */
996 tny_folder_copy_async (folder,
998 tny_folder_get_name (folder),
1001 transfer_folder_status_cb,
1007 /* ******************************************************************* */
1008 /* ************************** MSG ACTIONS ************************* */
1009 /* ******************************************************************* */
1011 void modest_mail_operation_get_msg (ModestMailOperation *self,
1013 GetMsgAsynUserCallback user_callback,
1016 GetMsgAsyncHelper *helper = NULL;
1018 ModestMailOperationPrivate *priv;
1020 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1021 g_return_if_fail (TNY_IS_HEADER (header));
1023 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1024 folder = tny_header_get_folder (header);
1026 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1028 /* Get message from folder */
1030 helper = g_slice_new0 (GetMsgAsyncHelper);
1031 helper->mail_op = self;
1032 helper->user_callback = user_callback;
1033 helper->pending_ops = 1;
1034 helper->user_data = user_data;
1036 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1038 g_object_unref (G_OBJECT (folder));
1040 /* Set status failed and set an error */
1041 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1042 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1043 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1044 _("Error trying to get a message. No folder found for header"));
1049 get_msg_cb (TnyFolder *folder,
1055 GetMsgAsyncHelper *helper = NULL;
1056 ModestMailOperation *self = NULL;
1057 ModestMailOperationPrivate *priv = NULL;
1059 helper = (GetMsgAsyncHelper *) user_data;
1060 g_return_if_fail (helper != NULL);
1061 self = helper->mail_op;
1062 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1063 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1065 helper->pending_ops--;
1067 /* Check errors and cancel */
1069 priv->error = g_error_copy (*error);
1070 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1074 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1075 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1076 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1077 _("Error trying to refresh the contents of %s"),
1078 tny_folder_get_name (folder));
1082 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1084 /* If user defined callback function was defined, call it */
1085 if (helper->user_callback) {
1086 helper->user_callback (priv->source, msg, helper->user_data);
1091 if (helper->pending_ops == 0) {
1092 g_slice_free (GetMsgAsyncHelper, helper);
1094 /* Notify the queue */
1095 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1100 get_msg_status_cb (GObject *obj,
1104 GetMsgAsyncHelper *helper = NULL;
1105 ModestMailOperation *self;
1106 ModestMailOperationPrivate *priv;
1108 g_return_if_fail (status != NULL);
1109 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1111 helper = (GetMsgAsyncHelper *) user_data;
1112 g_return_if_fail (helper != NULL);
1114 /* Temporary FIX: useful when tinymail send us status
1115 information *after* calling the function callback */
1116 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1119 self = helper->mail_op;
1120 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1122 if ((status->position == 1) && (status->of_total == 100))
1128 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1132 void modest_mail_operation_process_msg (ModestMailOperation *self,
1133 TnyList *header_list,
1134 GetMsgAsynUserCallback user_callback,
1137 ModestMailOperationPrivate *priv = NULL;
1138 GetMsgAsyncHelper *helper = NULL;
1139 TnyHeader *header = NULL;
1140 TnyFolder *folder = NULL;
1141 TnyIterator *iter = NULL;
1143 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1145 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1146 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1148 iter = tny_list_create_iterator (header_list);
1150 priv->total = tny_list_get_length(header_list);
1152 helper = g_slice_new0 (GetMsgAsyncHelper);
1153 helper->mail_op = self;
1154 helper->user_callback = user_callback;
1155 helper->pending_ops = priv->total;
1156 helper->user_data = user_data;
1158 while (!tny_iterator_is_done (iter)) {
1160 header = TNY_HEADER (tny_iterator_get_current (iter));
1161 folder = tny_header_get_folder (header);
1163 /* Get message from folder */
1165 /* The callback will call it per each header */
1166 tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1167 g_object_unref (G_OBJECT (folder));
1169 /* Set status failed and set an error */
1170 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1171 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1172 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1173 _("Error trying to get a message. No folder found for header"));
1175 /* Notify the queue */
1176 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1179 g_slice_free (GetMsgAsyncHelper, helper);
1183 g_object_unref (header);
1184 tny_iterator_next (iter);
1189 update_process_msg_status_cb (GObject *obj,
1193 GetMsgAsyncHelper *helper = NULL;
1194 ModestMailOperation *self;
1195 ModestMailOperationPrivate *priv;
1197 g_return_if_fail (status != NULL);
1198 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1200 helper = (GetMsgAsyncHelper *) user_data;
1201 g_return_if_fail (helper != NULL);
1203 /* Temporary FIX: useful when tinymail send us status
1204 information *after* calling the function callback */
1205 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1208 self = helper->mail_op;
1209 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1211 if ((status->position == 1) && (status->of_total == 100))
1214 if (status->of_total > 0)
1215 priv->done += status->position/status->of_total;
1217 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1223 modest_mail_operation_remove_msg (ModestMailOperation *self,
1225 gboolean remove_to_trash)
1228 ModestMailOperationPrivate *priv;
1230 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1231 g_return_if_fail (TNY_IS_HEADER (header));
1233 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1234 folder = tny_header_get_folder (header);
1236 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1238 /* Delete or move to trash */
1239 if (remove_to_trash) {
1240 TnyFolder *trash_folder;
1241 TnyStoreAccount *store_account;
1243 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1244 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1245 TNY_FOLDER_TYPE_TRASH);
1250 headers = tny_simple_list_new ();
1251 tny_list_append (headers, G_OBJECT (header));
1252 g_object_unref (header);
1255 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1256 g_object_unref (headers);
1257 /* g_object_unref (trash_folder); */
1259 ModestMailOperationPrivate *priv;
1261 /* Set status failed and set an error */
1262 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1263 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1264 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1265 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1266 _("Error trying to delete a message. Trash folder not found"));
1269 g_object_unref (G_OBJECT (store_account));
1271 tny_folder_remove_msg (folder, header, &(priv->error));
1273 tny_folder_sync(folder, TRUE, &(priv->error));
1278 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1280 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1283 g_object_unref (G_OBJECT (folder));
1285 /* Notify the queue */
1286 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1290 transfer_msgs_status_cb (GObject *obj,
1294 XFerMsgAsyncHelper *helper = NULL;
1295 ModestMailOperation *self;
1296 ModestMailOperationPrivate *priv;
1298 g_return_if_fail (status != NULL);
1299 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1301 helper = (XFerMsgAsyncHelper *) user_data;
1302 g_return_if_fail (helper != NULL);
1304 /* Temporary FIX: useful when tinymail send us status
1305 information *after* calling the function callback */
1306 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1309 self = helper->mail_op;
1310 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1312 if ((status->position == 1) && (status->of_total == 100))
1315 priv->done = status->position;
1316 priv->total = status->of_total;
1318 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1323 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1325 XFerMsgAsyncHelper *helper;
1326 ModestMailOperation *self;
1327 ModestMailOperationPrivate *priv;
1329 helper = (XFerMsgAsyncHelper *) user_data;
1330 self = helper->mail_op;
1332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1335 priv->error = g_error_copy (*err);
1337 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1338 } else if (cancelled) {
1339 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1340 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1341 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1342 _("Error trying to refresh the contents of %s"),
1343 tny_folder_get_name (folder));
1346 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1349 /* If user defined callback function was defined, call it */
1350 if (helper->user_callback) {
1351 helper->user_callback (priv->source, helper->user_data);
1355 g_object_unref (helper->headers);
1356 g_object_unref (helper->dest_folder);
1357 g_object_unref (helper->mail_op);
1358 g_slice_free (XFerMsgAsyncHelper, helper);
1359 g_object_unref (folder);
1361 /* Notify the queue */
1362 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1366 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1369 gboolean delete_original,
1370 XferMsgsAsynUserCallback user_callback,
1373 ModestMailOperationPrivate *priv;
1375 TnyFolder *src_folder;
1376 XFerMsgAsyncHelper *helper;
1379 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1380 g_return_if_fail (TNY_IS_LIST (headers));
1381 g_return_if_fail (TNY_IS_FOLDER (folder));
1383 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1386 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1388 /* Create the helper */
1389 helper = g_slice_new0 (XFerMsgAsyncHelper);
1390 helper->mail_op = g_object_ref(self);
1391 helper->dest_folder = g_object_ref(folder);
1392 helper->headers = g_object_ref(headers);
1393 helper->user_callback = user_callback;
1394 helper->user_data = user_data;
1396 /* Get source folder */
1397 iter = tny_list_create_iterator (headers);
1398 header = TNY_HEADER (tny_iterator_get_current (iter));
1399 src_folder = tny_header_get_folder (header);
1400 g_object_unref (header);
1401 g_object_unref (iter);
1403 /* Transfer messages */
1404 tny_folder_transfer_msgs_async (src_folder,
1409 transfer_msgs_status_cb,
1415 on_refresh_folder (TnyFolder *folder,
1420 ModestMailOperation *self;
1421 ModestMailOperationPrivate *priv;
1423 self = MODEST_MAIL_OPERATION (user_data);
1424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1427 priv->error = g_error_copy (*error);
1428 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1433 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1434 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1435 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1436 _("Error trying to refresh the contents of %s"),
1437 tny_folder_get_name (folder));
1441 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1445 g_object_unref (folder);
1447 /* Notify the queue */
1448 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1452 on_refresh_folder_status_update (GObject *obj,
1456 ModestMailOperation *self;
1457 ModestMailOperationPrivate *priv;
1459 g_return_if_fail (status != NULL);
1460 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1462 /* Temporary FIX: useful when tinymail send us status
1463 information *after* calling the function callback */
1464 if (!MODEST_IS_MAIL_OPERATION (user_data))
1467 self = MODEST_MAIL_OPERATION (user_data);
1468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1470 priv->done = status->position;
1471 priv->total = status->of_total;
1473 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1477 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1480 ModestMailOperationPrivate *priv;
1482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1484 /* Pick a reference */
1485 g_object_ref (folder);
1487 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1489 /* Refresh the folder. TODO: tinymail could issue a status
1490 updates before the callback call then this could happen. We
1491 must review the design */
1492 tny_folder_refresh_async (folder,
1494 on_refresh_folder_status_update,
1499 _modest_mail_operation_notify_end (ModestMailOperation *self)
1501 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);