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;
566 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
567 g_return_val_if_fail (account_name, FALSE);
569 /* Init mail operation. Set total and done to 0, and do not
570 update them, this way the progress objects will know that
571 we have no clue about the number of the objects */
572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
575 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
577 /* Get the Modest account */
578 modest_account = (TnyStoreAccount *)
579 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
581 TNY_ACCOUNT_TYPE_STORE);
583 if (!modest_account) {
584 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
585 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
586 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
587 "cannot get tny store account for %s\n", account_name);
588 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
593 /* Get the transport account, we can not do it in the thread
594 due to some problems with dbus */
595 transport_account = (TnyTransportAccount *)
596 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
598 if (!transport_account) {
599 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
600 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
601 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
602 "cannot get tny transport account for %s\n", account_name);
603 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
608 /* Create the helper object */
609 info = g_slice_new (UpdateAccountInfo);
610 info->mail_op = g_object_ref (self);
611 info->account = modest_account;
612 info->transport_account = transport_account;
614 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
619 ModestMailOperationStatus
620 modest_mail_operation_get_status (ModestMailOperation *self)
622 ModestMailOperationPrivate *priv;
624 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
625 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
626 MODEST_MAIL_OPERATION_STATUS_INVALID);
628 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
633 modest_mail_operation_get_error (ModestMailOperation *self)
635 ModestMailOperationPrivate *priv;
637 g_return_val_if_fail (self, NULL);
638 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
645 modest_mail_operation_cancel (ModestMailOperation *self)
647 ModestMailOperationPrivate *priv;
649 if (!MODEST_IS_MAIL_OPERATION (self)) {
650 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
654 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
656 /* TODO: Tinymail does not support cancel operation */
659 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
661 /* Notify the queue */
662 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
668 modest_mail_operation_get_task_done (ModestMailOperation *self)
670 ModestMailOperationPrivate *priv;
672 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
674 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
679 modest_mail_operation_get_task_total (ModestMailOperation *self)
681 ModestMailOperationPrivate *priv;
683 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
685 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
690 modest_mail_operation_is_finished (ModestMailOperation *self)
692 ModestMailOperationPrivate *priv;
693 gboolean retval = FALSE;
695 if (!MODEST_IS_MAIL_OPERATION (self)) {
696 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
700 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
702 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
703 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
704 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
705 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
714 /* ******************************************************************* */
715 /* ************************** STORE ACTIONS ************************* */
716 /* ******************************************************************* */
720 modest_mail_operation_create_folder (ModestMailOperation *self,
721 TnyFolderStore *parent,
724 ModestTnyFolderRules rules;
725 ModestMailOperationPrivate *priv;
726 TnyFolder *new_folder = NULL;
727 gboolean can_create = FALSE;
729 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
730 g_return_val_if_fail (name, NULL);
732 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
735 if (!TNY_IS_FOLDER (parent)) {
736 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
737 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
738 _("mail_in_ui_folder_create_error"));
740 /* Check folder rules */
741 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
742 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
743 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
744 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
745 _("mail_in_ui_folder_create_error"));
751 /* Create the folder */
752 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
753 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
756 /* Notify the queue */
757 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
763 modest_mail_operation_remove_folder (ModestMailOperation *self,
765 gboolean remove_to_trash)
768 ModestMailOperationPrivate *priv;
769 ModestTnyFolderRules rules;
771 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
772 g_return_if_fail (TNY_IS_FOLDER (folder));
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_DELETABLE) {
779 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
780 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
781 _("mail_in_ui_folder_delete_error"));
785 /* Get the account */
786 account = tny_folder_get_account (folder);
788 /* Delete folder or move to trash */
789 if (remove_to_trash) {
790 TnyFolder *trash_folder = NULL;
791 /* TnyFolder *trash_folder, *new_folder; */
792 trash_folder = modest_tny_account_get_special_folder (account,
793 TNY_FOLDER_TYPE_TRASH);
794 /* TODO: error_handling */
795 modest_mail_operation_xfer_folder (self, folder,
796 TNY_FOLDER_STORE (trash_folder), TRUE);
797 /* new_folder = modest_mail_operation_xfer_folder (self, folder, */
798 /* TNY_FOLDER_STORE (trash_folder), TRUE); */
799 /* g_object_unref (G_OBJECT (new_folder)); */
801 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
803 tny_folder_store_remove_folder (parent, folder, &(priv->error));
804 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
807 g_object_unref (G_OBJECT (parent));
809 g_object_unref (G_OBJECT (account));
812 /* Notify the queue */
813 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
817 modest_mail_operation_rename_folder (ModestMailOperation *self,
821 ModestMailOperationPrivate *priv;
822 ModestTnyFolderRules rules;
824 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
825 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
826 g_return_if_fail (name);
828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
830 /* Check folder rules */
831 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
832 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
833 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
834 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
835 _("FIXME: unable to rename"));
837 /* Rename. Camel handles folder subscription/unsubscription */
838 tny_folder_set_name (folder, name, &(priv->error));
839 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
842 /* Notify the queue */
843 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
847 transfer_folder_status_cb (GObject *obj,
851 XFerMsgAsyncHelper *helper = NULL;
852 ModestMailOperation *self;
853 ModestMailOperationPrivate *priv;
855 g_return_if_fail (status != NULL);
856 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
858 helper = (XFerMsgAsyncHelper *) user_data;
859 g_return_if_fail (helper != NULL);
861 /* Temporary FIX: useful when tinymail send us status
862 information *after* calling the function callback */
863 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
866 self = helper->mail_op;
867 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
869 if ((status->position == 1) && (status->of_total == 100))
872 priv->done = status->position;
873 priv->total = status->of_total;
876 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
881 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
883 XFerFolderAsyncHelper *helper = NULL;
884 ModestMailOperation *self = NULL;
885 ModestMailOperationPrivate *priv = NULL;
887 helper = (XFerFolderAsyncHelper *) user_data;
888 self = helper->mail_op;
890 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
893 priv->error = g_error_copy (*err);
895 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
896 } else if (cancelled) {
897 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
898 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
899 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
900 _("Error trying to refresh the contents of %s"),
901 tny_folder_get_name (folder));
904 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
908 g_slice_free (XFerFolderAsyncHelper, helper);
909 g_object_unref (folder);
910 g_object_unref (into);
911 g_object_unref (new_folder);
913 /* Notify the queue */
914 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
918 modest_mail_operation_xfer_folder (ModestMailOperation *self,
920 TnyFolderStore *parent,
921 gboolean delete_original)
923 ModestMailOperationPrivate *priv;
924 TnyFolder *new_folder = NULL;
925 ModestTnyFolderRules rules;
927 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
928 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
929 g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
931 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
933 /* The moveable restriction is applied also to copy operation */
934 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
935 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
936 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
937 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
938 _("FIXME: unable to rename"));
940 /* Move/Copy folder */
941 new_folder = tny_folder_copy (folder,
943 tny_folder_get_name (folder),
948 /* Notify the queue */
949 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
955 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
957 TnyFolderStore *parent,
958 gboolean delete_original)
960 XFerFolderAsyncHelper *helper = NULL;
961 ModestMailOperationPrivate *priv = NULL;
962 ModestTnyFolderRules rules;
964 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
965 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
966 g_return_if_fail (TNY_IS_FOLDER (folder));
968 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
970 /* The moveable restriction is applied also to copy operation */
971 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
972 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
973 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
974 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
975 _("FIXME: unable to rename"));
977 helper = g_slice_new0 (XFerFolderAsyncHelper);
978 helper->mail_op = self;
980 /* Move/Copy folder */
981 tny_folder_copy_async (folder,
983 tny_folder_get_name (folder),
986 transfer_folder_status_cb,
992 /* ******************************************************************* */
993 /* ************************** MSG ACTIONS ************************* */
994 /* ******************************************************************* */
996 void modest_mail_operation_get_msg (ModestMailOperation *self,
998 GetMsgAsynUserCallback user_callback,
1001 GetMsgAsyncHelper *helper = NULL;
1003 ModestMailOperationPrivate *priv;
1005 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1006 g_return_if_fail (TNY_IS_HEADER (header));
1008 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1009 folder = tny_header_get_folder (header);
1011 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1013 /* Get message from folder */
1015 helper = g_slice_new0 (GetMsgAsyncHelper);
1016 helper->mail_op = self;
1017 helper->user_callback = user_callback;
1018 helper->pending_ops = 1;
1019 helper->user_data = user_data;
1021 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1023 g_object_unref (G_OBJECT (folder));
1025 /* Set status failed and set an error */
1026 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1027 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1028 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1029 _("Error trying to get a message. No folder found for header"));
1034 get_msg_cb (TnyFolder *folder,
1040 GetMsgAsyncHelper *helper = NULL;
1041 ModestMailOperation *self = NULL;
1042 ModestMailOperationPrivate *priv = NULL;
1044 helper = (GetMsgAsyncHelper *) user_data;
1045 g_return_if_fail (helper != NULL);
1046 self = helper->mail_op;
1047 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1050 helper->pending_ops--;
1052 /* Check errors and cancel */
1054 priv->error = g_error_copy (*error);
1055 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1059 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1060 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1061 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1062 _("Error trying to refresh the contents of %s"),
1063 tny_folder_get_name (folder));
1067 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1069 /* If user defined callback function was defined, call it */
1070 if (helper->user_callback) {
1071 helper->user_callback (priv->source, msg, helper->user_data);
1076 if (helper->pending_ops == 0) {
1077 g_slice_free (GetMsgAsyncHelper, helper);
1079 /* Notify the queue */
1080 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1085 get_msg_status_cb (GObject *obj,
1089 GetMsgAsyncHelper *helper = NULL;
1090 ModestMailOperation *self;
1091 ModestMailOperationPrivate *priv;
1093 g_return_if_fail (status != NULL);
1094 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1096 helper = (GetMsgAsyncHelper *) user_data;
1097 g_return_if_fail (helper != NULL);
1099 /* Temporary FIX: useful when tinymail send us status
1100 information *after* calling the function callback */
1101 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1104 self = helper->mail_op;
1105 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1107 if ((status->position == 1) && (status->of_total == 100))
1113 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1117 void modest_mail_operation_process_msg (ModestMailOperation *self,
1118 TnyList *header_list,
1119 GetMsgAsynUserCallback user_callback,
1122 ModestMailOperationPrivate *priv = NULL;
1123 GetMsgAsyncHelper *helper = NULL;
1124 TnyHeader *header = NULL;
1125 TnyFolder *folder = NULL;
1126 TnyIterator *iter = NULL;
1128 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1130 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1131 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1133 iter = tny_list_create_iterator (header_list);
1135 priv->total = tny_list_get_length(header_list);
1137 helper = g_slice_new0 (GetMsgAsyncHelper);
1138 helper->mail_op = self;
1139 helper->user_callback = user_callback;
1140 helper->pending_ops = priv->total;
1141 helper->user_data = user_data;
1143 while (!tny_iterator_is_done (iter)) {
1145 header = TNY_HEADER (tny_iterator_get_current (iter));
1146 folder = tny_header_get_folder (header);
1148 /* Get message from folder */
1150 /* The callback will call it per each header */
1151 tny_folder_get_msg_async (folder, header, get_msg_cb, update_process_msg_status_cb, helper);
1152 g_object_unref (G_OBJECT (folder));
1154 /* Set status failed and set an error */
1155 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1156 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1157 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1158 _("Error trying to get a message. No folder found for header"));
1160 /* Notify the queue */
1161 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1164 g_slice_free (GetMsgAsyncHelper, helper);
1168 g_object_unref (header);
1169 tny_iterator_next (iter);
1174 update_process_msg_status_cb (GObject *obj,
1178 GetMsgAsyncHelper *helper = NULL;
1179 ModestMailOperation *self;
1180 ModestMailOperationPrivate *priv;
1182 g_return_if_fail (status != NULL);
1183 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1185 helper = (GetMsgAsyncHelper *) user_data;
1186 g_return_if_fail (helper != NULL);
1188 /* Temporary FIX: useful when tinymail send us status
1189 information *after* calling the function callback */
1190 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1193 self = helper->mail_op;
1194 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1196 if ((status->position == 1) && (status->of_total == 100))
1199 if (status->of_total > 0)
1200 priv->done += status->position/status->of_total;
1202 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1208 modest_mail_operation_remove_msg (ModestMailOperation *self,
1210 gboolean remove_to_trash)
1213 ModestMailOperationPrivate *priv;
1215 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1216 g_return_if_fail (TNY_IS_HEADER (header));
1218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1219 folder = tny_header_get_folder (header);
1221 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1223 /* Delete or move to trash */
1224 if (remove_to_trash) {
1225 TnyFolder *trash_folder;
1226 TnyStoreAccount *store_account;
1228 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1229 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1230 TNY_FOLDER_TYPE_TRASH);
1235 headers = tny_simple_list_new ();
1236 tny_list_append (headers, G_OBJECT (header));
1237 g_object_unref (header);
1240 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE);
1241 g_object_unref (headers);
1242 /* g_object_unref (trash_folder); */
1244 ModestMailOperationPrivate *priv;
1246 /* Set status failed and set an error */
1247 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1248 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1249 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1250 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1251 _("Error trying to delete a message. Trash folder not found"));
1254 g_object_unref (G_OBJECT (store_account));
1256 tny_folder_remove_msg (folder, header, &(priv->error));
1258 tny_folder_sync(folder, TRUE, &(priv->error));
1263 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1265 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1268 g_object_unref (G_OBJECT (folder));
1270 /* Notify the queue */
1271 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1275 transfer_msgs_status_cb (GObject *obj,
1279 XFerMsgAsyncHelper *helper = NULL;
1280 ModestMailOperation *self;
1281 ModestMailOperationPrivate *priv;
1283 g_return_if_fail (status != NULL);
1284 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1286 helper = (XFerMsgAsyncHelper *) user_data;
1287 g_return_if_fail (helper != NULL);
1289 /* Temporary FIX: useful when tinymail send us status
1290 information *after* calling the function callback */
1291 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1294 self = helper->mail_op;
1295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1297 if ((status->position == 1) && (status->of_total == 100))
1300 priv->done = status->position;
1301 priv->total = status->of_total;
1303 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1308 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1310 XFerMsgAsyncHelper *helper;
1311 ModestMailOperation *self;
1312 ModestMailOperationPrivate *priv;
1314 helper = (XFerMsgAsyncHelper *) user_data;
1315 self = helper->mail_op;
1317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1320 priv->error = g_error_copy (*err);
1322 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1323 } else if (cancelled) {
1324 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1325 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1326 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1327 _("Error trying to refresh the contents of %s"),
1328 tny_folder_get_name (folder));
1331 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1335 /* g_object_unref (helper->headers); */
1336 /* g_object_unref (helper->dest_folder); */
1337 /* g_object_unref (helper->mail_op); */
1338 g_slice_free (XFerMsgAsyncHelper, helper);
1339 g_object_unref (folder);
1341 /* Notify the queue */
1342 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1346 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1349 gboolean delete_original)
1351 ModestMailOperationPrivate *priv;
1353 TnyFolder *src_folder;
1354 XFerMsgAsyncHelper *helper;
1357 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1358 g_return_if_fail (TNY_IS_LIST (headers));
1359 g_return_if_fail (TNY_IS_FOLDER (folder));
1361 /* Pick references for async calls */
1362 g_object_ref (folder);
1364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1367 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1369 /* Create the helper */
1370 helper = g_slice_new0 (XFerMsgAsyncHelper);
1371 helper->mail_op = self;
1372 helper->dest_folder = g_object_ref(folder);
1373 helper->headers = g_object_ref(headers);
1375 /* Get source folder */
1376 iter = tny_list_create_iterator (headers);
1377 header = TNY_HEADER (tny_iterator_get_current (iter));
1378 src_folder = tny_header_get_folder (header);
1379 g_object_unref (header);
1380 g_object_unref (iter);
1382 /* Transfer messages */
1383 tny_folder_transfer_msgs_async (src_folder,
1388 transfer_msgs_status_cb,
1394 on_refresh_folder (TnyFolder *folder,
1399 ModestMailOperation *self;
1400 ModestMailOperationPrivate *priv;
1402 self = MODEST_MAIL_OPERATION (user_data);
1403 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1406 priv->error = g_error_copy (*error);
1407 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1412 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1413 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1414 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1415 _("Error trying to refresh the contents of %s"),
1416 tny_folder_get_name (folder));
1420 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1424 g_object_unref (folder);
1426 /* Notify the queue */
1427 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1431 on_refresh_folder_status_update (GObject *obj,
1435 ModestMailOperation *self;
1436 ModestMailOperationPrivate *priv;
1438 g_return_if_fail (status != NULL);
1439 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1441 /* Temporary FIX: useful when tinymail send us status
1442 information *after* calling the function callback */
1443 if (!MODEST_IS_MAIL_OPERATION (user_data))
1446 self = MODEST_MAIL_OPERATION (user_data);
1447 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1449 priv->done = status->position;
1450 priv->total = status->of_total;
1452 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1456 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1459 ModestMailOperationPrivate *priv;
1461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1463 /* Pick a reference */
1464 g_object_ref (folder);
1466 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1468 /* Refresh the folder. TODO: tinymail could issue a status
1469 updates before the callback call then this could happen. We
1470 must review the design */
1471 tny_folder_refresh_async (folder,
1473 on_refresh_folder_status_update,
1478 _modest_mail_operation_notify_end (ModestMailOperation *self)
1480 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);