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 <tny-folder-observer.h>
43 #include <camel/camel-stream-mem.h>
44 #include <glib/gi18n.h>
45 #include "modest-platform.h"
46 #include <modest-tny-account.h>
47 #include <modest-tny-send-queue.h>
48 #include <modest-runtime.h>
49 #include "modest-text-utils.h"
50 #include "modest-tny-msg.h"
51 #include "modest-tny-folder.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-marshal.h"
54 #include "modest-error.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 enum _ModestMailOperationSignals
77 PROGRESS_CHANGED_SIGNAL,
82 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
83 struct _ModestMailOperationPrivate {
89 ErrorCheckingUserCallback error_checking;
90 ModestMailOperationStatus status;
91 ModestMailOperationTypeOperation op_type;
94 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95 MODEST_TYPE_MAIL_OPERATION, \
96 ModestMailOperationPrivate))
98 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
99 priv->status = new_status;\
102 typedef struct _GetMsgAsyncHelper {
103 ModestMailOperation *mail_op;
104 GetMsgAsyncUserCallback user_callback;
109 typedef struct _XFerMsgAsyncHelper
111 ModestMailOperation *mail_op;
113 TnyFolder *dest_folder;
114 XferMsgsAsynUserCallback user_callback;
116 } XFerMsgAsyncHelper;
118 typedef struct _XFerFolderAsyncHelper
120 ModestMailOperation *mail_op;
122 } XFerFolderAsyncHelper;
125 static GObjectClass *parent_class = NULL;
127 static guint signals[NUM_SIGNALS] = {0};
130 modest_mail_operation_get_type (void)
132 static GType my_type = 0;
134 static const GTypeInfo my_info = {
135 sizeof(ModestMailOperationClass),
136 NULL, /* base init */
137 NULL, /* base finalize */
138 (GClassInitFunc) modest_mail_operation_class_init,
139 NULL, /* class finalize */
140 NULL, /* class data */
141 sizeof(ModestMailOperation),
143 (GInstanceInitFunc) modest_mail_operation_init,
146 my_type = g_type_register_static (G_TYPE_OBJECT,
147 "ModestMailOperation",
154 modest_mail_operation_class_init (ModestMailOperationClass *klass)
156 GObjectClass *gobject_class;
157 gobject_class = (GObjectClass*) klass;
159 parent_class = g_type_class_peek_parent (klass);
160 gobject_class->finalize = modest_mail_operation_finalize;
162 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
165 * ModestMailOperation::progress-changed
166 * @self: the #MailOperation that emits the signal
167 * @user_data: user data set when the signal handler was connected
169 * Emitted when the progress of a mail operation changes
171 signals[PROGRESS_CHANGED_SIGNAL] =
172 g_signal_new ("progress-changed",
173 G_TYPE_FROM_CLASS (gobject_class),
175 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
177 g_cclosure_marshal_VOID__POINTER,
178 G_TYPE_NONE, 1, G_TYPE_POINTER);
182 modest_mail_operation_init (ModestMailOperation *obj)
184 ModestMailOperationPrivate *priv;
186 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
188 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
191 priv->error_checking = NULL;
199 modest_mail_operation_finalize (GObject *obj)
201 ModestMailOperationPrivate *priv;
203 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
206 g_error_free (priv->error);
210 g_object_unref (priv->source);
214 G_OBJECT_CLASS(parent_class)->finalize (obj);
218 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
221 ModestMailOperation *obj;
222 ModestMailOperationPrivate *priv;
224 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
225 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
227 priv->op_type = op_type;
229 priv->source = g_object_ref(source);
235 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
237 ErrorCheckingUserCallback error_handler)
239 ModestMailOperation *obj;
240 ModestMailOperationPrivate *priv;
242 obj = modest_mail_operation_new (op_type, source);
243 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
245 g_return_val_if_fail (error_handler != NULL, obj);
246 priv->error_checking = error_handler;
252 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
254 ModestMailOperationPrivate *priv;
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
257 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
259 if (priv->error_checking == NULL)
261 priv->error_checking (priv->source, self);
265 ModestMailOperationTypeOperation
266 modest_mail_operation_get_type_operation (ModestMailOperation *self)
268 ModestMailOperationPrivate *priv;
270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
272 return priv->op_type;
276 modest_mail_operation_is_mine (ModestMailOperation *self,
279 ModestMailOperationPrivate *priv;
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 if (priv->source == NULL) return FALSE;
284 return priv->source == me;
288 modest_mail_operation_get_source (ModestMailOperation *self)
290 ModestMailOperationPrivate *priv;
292 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 return g_object_ref (priv->source);
297 ModestMailOperationStatus
298 modest_mail_operation_get_status (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
303 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
304 MODEST_MAIL_OPERATION_STATUS_INVALID);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
311 modest_mail_operation_get_error (ModestMailOperation *self)
313 ModestMailOperationPrivate *priv;
315 g_return_val_if_fail (self, NULL);
316 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
323 modest_mail_operation_cancel (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 if (!MODEST_IS_MAIL_OPERATION (self)) {
328 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
334 /* TODO: Tinymail does not support cancel operation */
335 /* tny_account_cancel (); */
338 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
340 /* Notify about operation end */
341 modest_mail_operation_notify_end (self);
347 modest_mail_operation_get_task_done (ModestMailOperation *self)
349 ModestMailOperationPrivate *priv;
351 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
358 modest_mail_operation_get_task_total (ModestMailOperation *self)
360 ModestMailOperationPrivate *priv;
362 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
369 modest_mail_operation_is_finished (ModestMailOperation *self)
371 ModestMailOperationPrivate *priv;
372 gboolean retval = FALSE;
374 if (!MODEST_IS_MAIL_OPERATION (self)) {
375 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
382 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
384 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
394 modest_mail_operation_get_id (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
405 modest_mail_operation_set_id (ModestMailOperation *self,
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 * Creates an image of the current state of a mail operation, the
418 * caller must free it
420 static ModestMailOperationState *
421 modest_mail_operation_clone_state (ModestMailOperation *self)
423 ModestMailOperationState *state;
424 ModestMailOperationPrivate *priv;
426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
428 state = g_slice_new (ModestMailOperationState);
430 state->status = priv->status;
431 state->op_type = priv->op_type;
432 state->done = priv->done;
433 state->total = priv->total;
434 state->finished = modest_mail_operation_is_finished (self);
439 /* ******************************************************************* */
440 /* ************************** SEND ACTIONS ************************* */
441 /* ******************************************************************* */
444 modest_mail_operation_send_mail (ModestMailOperation *self,
445 TnyTransportAccount *transport_account,
448 TnySendQueue *send_queue;
450 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
451 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
452 g_return_if_fail (TNY_IS_MSG (msg));
454 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
455 if (!TNY_IS_SEND_QUEUE(send_queue))
456 g_printerr ("modest: could not find send queue for account\n");
459 tny_send_queue_add (send_queue, msg, &err);
461 g_printerr ("modest: error adding msg to send queue: %s\n",
465 /* g_message ("modest: message added to send queue"); */
469 /* Notify about operation end */
470 modest_mail_operation_notify_end (self);
474 modest_mail_operation_send_new_mail (ModestMailOperation *self,
475 TnyTransportAccount *transport_account,
476 const gchar *from, const gchar *to,
477 const gchar *cc, const gchar *bcc,
478 const gchar *subject, const gchar *plain_body,
479 const gchar *html_body,
480 const GList *attachments_list,
481 TnyHeaderFlags priority_flags)
484 ModestMailOperationPrivate *priv = NULL;
485 /* GList *node = NULL; */
487 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
488 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
492 /* Check parametters */
494 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
495 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
496 _("Error trying to send a mail. You need to set at least one recipient"));
500 if (html_body == NULL) {
501 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
503 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
506 g_printerr ("modest: failed to create a new msg\n");
510 /* TODO: add priority handling. It's received in the priority_flags operator, and
511 it should have effect in the sending operation */
513 /* Call mail operation */
514 modest_mail_operation_send_mail (self, transport_account, new_msg);
517 g_object_unref (G_OBJECT (new_msg));
521 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
522 TnyTransportAccount *transport_account,
523 const gchar *from, const gchar *to,
524 const gchar *cc, const gchar *bcc,
525 const gchar *subject, const gchar *plain_body,
526 const gchar *html_body,
527 const GList *attachments_list,
528 TnyHeaderFlags priority_flags)
531 TnyFolder *folder = NULL;
532 ModestMailOperationPrivate *priv = NULL;
535 /* GList *node = NULL; */
537 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
538 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
542 if (html_body == NULL) {
543 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
545 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
548 g_printerr ("modest: failed to create a new msg\n");
552 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
554 g_printerr ("modest: failed to find Drafts folder\n");
558 tny_folder_add_msg (folder, msg, &err);
560 g_printerr ("modest: error adding msg to Drafts folder: %s",
566 modest_mail_operation_notify_end (self);
571 g_object_unref (G_OBJECT(msg));
573 g_object_unref (G_OBJECT(folder));
578 ModestMailOperation *mail_op;
579 TnyStoreAccount *account;
580 TnyTransportAccount *transport_account;
583 gchar *retrieve_type;
586 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
587 /* We use this folder observer to track the headers that have been
588 * added to a folder */
591 TnyList *new_headers;
592 } InternalFolderObserver;
596 } InternalFolderObserverClass;
598 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
600 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
601 internal_folder_observer,
603 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
607 foreach_add_item (gpointer header, gpointer user_data)
609 tny_list_prepend (TNY_LIST (user_data),
610 g_object_ref (G_OBJECT (header)));
613 /* This is the method that looks for new messages in a folder */
615 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
617 TnyFolderChangeChanged changed;
619 changed = tny_folder_change_get_changed (change);
621 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
624 /* Get added headers */
625 list = tny_simple_list_new ();
626 tny_folder_change_get_added_headers (change, list);
628 /* Add them to the folder observer */
629 tny_list_foreach (list, foreach_add_item,
630 ((InternalFolderObserver *)self)->new_headers);
632 g_object_unref (G_OBJECT (list));
637 internal_folder_observer_init (InternalFolderObserver *self)
639 self->new_headers = tny_simple_list_new ();
642 internal_folder_observer_finalize (GObject *object)
644 InternalFolderObserver *self;
646 self = (InternalFolderObserver *) object;
647 g_object_unref (self->new_headers);
649 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
652 tny_folder_observer_init (TnyFolderObserverIface *iface)
654 iface->update_func = internal_folder_observer_update;
657 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
659 GObjectClass *object_class;
661 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
662 object_class = (GObjectClass*) klass;
663 object_class->finalize = internal_folder_observer_finalize;
669 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
672 TnyList *folders = tny_simple_list_new ();
674 tny_folder_store_get_folders (store, folders, query, NULL);
675 iter = tny_list_create_iterator (folders);
677 while (!tny_iterator_is_done (iter)) {
679 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
681 tny_list_prepend (all_folders, G_OBJECT (folder));
682 recurse_folders (folder, query, all_folders);
683 g_object_unref (G_OBJECT (folder));
685 tny_iterator_next (iter);
687 g_object_unref (G_OBJECT (iter));
688 g_object_unref (G_OBJECT (folders));
692 * Issues the "progress-changed" signal. The timer won't be removed,
693 * so you must call g_source_remove to stop the signal emission
696 idle_notify_progress (gpointer data)
698 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
699 ModestMailOperationState *state;
701 state = modest_mail_operation_clone_state (mail_op);
702 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
703 g_slice_free (ModestMailOperationState, state);
709 * Issues the "progress-changed" signal and removes the timer. It uses
710 * a lock to ensure that the progress information of the mail
711 * operation is not modified while there are notifications pending
714 idle_notify_progress_once (gpointer data)
718 pair = (ModestPair *) data;
720 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
722 /* Free the state and the reference to the mail operation */
723 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
724 g_object_unref (pair->first);
730 * Used by update_account_thread to notify the queue from the main
731 * loop. We call it inside an idle call to achieve that
734 notify_update_account_queue (gpointer data)
736 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
738 modest_mail_operation_notify_end (mail_op);
739 g_object_unref (mail_op);
745 update_account_thread (gpointer thr_user_data)
747 UpdateAccountInfo *info;
748 TnyList *all_folders = NULL, *new_headers;
749 TnyIterator *iter = NULL;
750 TnyFolderStoreQuery *query = NULL;
751 ModestMailOperationPrivate *priv;
753 info = (UpdateAccountInfo *) thr_user_data;
754 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
756 /* Get all the folders We can do it synchronously because
757 we're already running in a different thread than the UI */
758 all_folders = tny_simple_list_new ();
759 query = tny_folder_store_query_new ();
760 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
761 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
766 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
770 iter = tny_list_create_iterator (all_folders);
771 while (!tny_iterator_is_done (iter)) {
772 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
774 recurse_folders (folder, query, all_folders);
775 tny_iterator_next (iter);
777 g_object_unref (G_OBJECT (iter));
779 /* Update status and notify. We need to call the notification
780 with a source functopm in order to call it from the main
781 loop. We need that in order not to get into trouble with
782 Gtk+. We use a timeout in order to provide more status
783 information, because the sync tinymail call does not
784 provide it for the moment */
785 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
787 /* Refresh folders */
788 new_headers = tny_simple_list_new ();
789 iter = tny_list_create_iterator (all_folders);
790 while (!tny_iterator_is_done (iter) && !priv->error) {
792 InternalFolderObserver *observer;
793 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
795 /* Refresh the folder */
796 observer = g_object_new (internal_folder_observer_get_type (), NULL);
797 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
798 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
800 /* If the retrieve type is headers only do nothing more */
801 if (!strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
802 !strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
805 iter = tny_list_create_iterator (observer->new_headers);
806 while (!tny_iterator_is_done (iter)) {
807 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
808 /* Apply per-message size limits */
809 if (tny_header_get_message_size (header) < info->max_size)
810 tny_list_prepend (new_headers, G_OBJECT (header));
812 g_object_unref (header);
813 tny_iterator_next (iter);
815 g_object_unref (iter);
817 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
818 g_object_unref (observer);
821 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
823 g_object_unref (G_OBJECT (folder));
824 tny_iterator_next (iter);
826 g_object_unref (G_OBJECT (iter));
827 g_source_remove (timeout);
830 /* Apply message count limit */
831 /* TODO if the number of messages exceeds the maximum, ask the
832 user to download them all */
834 priv->total = MIN (tny_list_get_length (new_headers), info->retrieve_limit);
835 iter = tny_list_create_iterator (new_headers);
836 while ((msg_num < info->retrieve_limit) && !tny_iterator_is_done (iter)) {
838 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
839 TnyFolder *folder = tny_header_get_folder (header);
840 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
841 ModestMailOperationState *state;
845 /* We can not just use the mail operation because the
846 values of done and total could change before the
848 state = modest_mail_operation_clone_state (info->mail_op);
849 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
850 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
851 pair, (GDestroyNotify) modest_pair_free);
853 g_object_unref (msg);
854 g_object_unref (folder);
855 g_object_unref (header);
858 tny_iterator_next (iter);
860 g_object_unref (iter);
861 g_object_unref (new_headers);
865 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
869 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
870 (info->transport_account);
872 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
873 /* TODO: Is this meant to block? */
874 modest_tny_send_queue_try_to_send (send_queue);
875 g_source_remove (timeout);
877 g_object_unref (G_OBJECT(send_queue));
879 /* Check if the operation was a success */
881 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
883 /* Update the last updated key */
884 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
885 tny_account_get_id (TNY_ACCOUNT (info->account)),
886 MODEST_ACCOUNT_LAST_UPDATED,
892 /* Notify about operation end. Note that the info could be
893 freed before this idle happens, but the mail operation will
895 g_idle_add (notify_update_account_queue, info->mail_op);
898 g_object_unref (query);
899 g_object_unref (all_folders);
900 g_object_unref (info->account);
901 g_object_unref (info->transport_account);
902 g_free (info->retrieve_type);
903 g_slice_free (UpdateAccountInfo, info);
909 modest_mail_operation_update_account (ModestMailOperation *self,
910 const gchar *account_name)
913 UpdateAccountInfo *info;
914 ModestMailOperationPrivate *priv;
915 ModestAccountMgr *mgr;
916 TnyStoreAccount *modest_account;
917 TnyTransportAccount *transport_account;
919 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
920 g_return_val_if_fail (account_name, FALSE);
922 /* Init mail operation. Set total and done to 0, and do not
923 update them, this way the progress objects will know that
924 we have no clue about the number of the objects */
925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
928 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
930 /* Get the Modest account */
931 modest_account = (TnyStoreAccount *)
932 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
934 TNY_ACCOUNT_TYPE_STORE);
936 if (!modest_account) {
937 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
938 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
939 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
940 "cannot get tny store account for %s\n", account_name);
941 modest_mail_operation_notify_end (self);
945 /* Get the transport account, we can not do it in the thread
946 due to some problems with dbus */
947 transport_account = (TnyTransportAccount *)
948 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
950 if (!transport_account) {
951 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
952 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
953 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
954 "cannot get tny transport account for %s\n", account_name);
955 modest_mail_operation_notify_end (self);
959 /* Create the helper object */
960 info = g_slice_new (UpdateAccountInfo);
961 info->mail_op = self;
962 info->account = modest_account;
963 info->transport_account = transport_account;
965 /* Get the message size limit */
966 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
967 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
968 if (info->max_size == 0)
969 info->max_size = G_MAXINT;
971 info->max_size = info->max_size * KB;
973 /* Get per-account retrieval type */
974 mgr = modest_runtime_get_account_mgr ();
975 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
976 MODEST_ACCOUNT_RETRIEVE, FALSE);
978 /* Get per-account message amount retrieval limit */
979 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
980 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
981 if (info->retrieve_limit == 0)
982 info->retrieve_limit = G_MAXINT;
984 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
989 /* ******************************************************************* */
990 /* ************************** STORE ACTIONS ************************* */
991 /* ******************************************************************* */
995 modest_mail_operation_create_folder (ModestMailOperation *self,
996 TnyFolderStore *parent,
999 ModestTnyFolderRules rules;
1000 ModestMailOperationPrivate *priv;
1001 TnyFolder *new_folder = NULL;
1002 gboolean can_create = FALSE;
1004 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1005 g_return_val_if_fail (name, NULL);
1007 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1010 if (!TNY_IS_FOLDER (parent)) {
1011 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1012 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1013 _("mail_in_ui_folder_create_error"));
1015 /* Check folder rules */
1016 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1017 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
1018 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1019 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1020 _("mail_in_ui_folder_create_error"));
1026 /* Create the folder */
1027 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1028 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1031 /* Notify about operation end */
1032 modest_mail_operation_notify_end (self);
1038 modest_mail_operation_remove_folder (ModestMailOperation *self,
1040 gboolean remove_to_trash)
1042 TnyAccount *account;
1043 ModestMailOperationPrivate *priv;
1044 ModestTnyFolderRules rules;
1046 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1047 g_return_if_fail (TNY_IS_FOLDER (folder));
1049 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1051 /* Check folder rules */
1052 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1053 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1055 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1056 _("mail_in_ui_folder_delete_error"));
1060 /* Get the account */
1061 account = tny_folder_get_account (folder);
1063 /* Delete folder or move to trash */
1064 if (remove_to_trash) {
1065 TnyFolder *trash_folder = NULL;
1066 trash_folder = modest_tny_account_get_special_folder (account,
1067 TNY_FOLDER_TYPE_TRASH);
1068 /* TODO: error_handling */
1069 modest_mail_operation_xfer_folder (self, folder,
1070 TNY_FOLDER_STORE (trash_folder), TRUE);
1072 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1074 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1075 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1078 g_object_unref (G_OBJECT (parent));
1080 g_object_unref (G_OBJECT (account));
1083 /* Notify about operation end */
1084 modest_mail_operation_notify_end (self);
1088 modest_mail_operation_rename_folder (ModestMailOperation *self,
1092 ModestMailOperationPrivate *priv;
1093 ModestTnyFolderRules rules;
1095 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1096 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1097 g_return_if_fail (name);
1099 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1101 /* Check folder rules */
1102 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1103 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1104 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1105 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1106 _("FIXME: unable to rename"));
1108 /* Rename. Camel handles folder subscription/unsubscription */
1109 TnyFolderStore *into;
1112 into = tny_folder_get_folder_store (folder);
1113 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
1115 g_object_unref (into);
1117 g_object_unref (nfol);
1119 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1123 /* Notify about operation end */
1124 modest_mail_operation_notify_end (self);
1128 transfer_folder_status_cb (GObject *obj,
1132 XFerMsgAsyncHelper *helper = NULL;
1133 ModestMailOperation *self;
1134 ModestMailOperationPrivate *priv;
1135 ModestMailOperationState *state;
1137 g_return_if_fail (status != NULL);
1138 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1140 helper = (XFerMsgAsyncHelper *) user_data;
1141 g_return_if_fail (helper != NULL);
1143 self = helper->mail_op;
1144 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1146 if ((status->position == 1) && (status->of_total == 100))
1149 priv->done = status->position;
1150 priv->total = status->of_total;
1152 state = modest_mail_operation_clone_state (self);
1153 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1154 g_slice_free (ModestMailOperationState, state);
1159 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
1161 XFerFolderAsyncHelper *helper = NULL;
1162 ModestMailOperation *self = NULL;
1163 ModestMailOperationPrivate *priv = NULL;
1165 helper = (XFerFolderAsyncHelper *) user_data;
1166 self = helper->mail_op;
1168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1171 priv->error = g_error_copy (*err);
1173 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1174 } else if (cancelled) {
1175 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1176 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1177 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1178 _("Transference of %s was cancelled."),
1179 tny_folder_get_name (folder));
1182 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1186 g_slice_free (XFerFolderAsyncHelper, helper);
1187 g_object_unref (folder);
1188 g_object_unref (into);
1189 if (new_folder != NULL)
1190 g_object_unref (new_folder);
1192 /* Notify about operation end */
1193 modest_mail_operation_notify_end (self);
1197 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1199 TnyFolderStore *parent,
1200 gboolean delete_original)
1202 XFerFolderAsyncHelper *helper = NULL;
1203 ModestMailOperationPrivate *priv = NULL;
1204 ModestTnyFolderRules parent_rules, rules;
1206 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1207 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1208 g_return_if_fail (TNY_IS_FOLDER (folder));
1210 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1212 /* Pick references for async calls */
1213 g_object_ref (folder);
1214 g_object_ref (parent);
1216 /* Get folder rules */
1217 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1218 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1220 /* The moveable restriction is applied also to copy operation */
1221 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
1222 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1223 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1224 _("mail_in_ui_folder_move_target_error"));
1226 /* Notify the queue */
1227 modest_mail_operation_notify_end (self);
1228 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1229 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1230 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1231 _("FIXME: parent folder does not accept new folders"));
1233 /* Notify the queue */
1234 modest_mail_operation_notify_end (self);
1236 helper = g_slice_new0 (XFerFolderAsyncHelper);
1237 helper->mail_op = self;
1239 /* Move/Copy folder */
1240 tny_folder_copy_async (folder,
1242 tny_folder_get_name (folder),
1245 transfer_folder_status_cb,
1251 /* ******************************************************************* */
1252 /* ************************** MSG ACTIONS ************************* */
1253 /* ******************************************************************* */
1255 void modest_mail_operation_get_msg (ModestMailOperation *self,
1257 GetMsgAsyncUserCallback user_callback,
1260 GetMsgAsyncHelper *helper = NULL;
1262 ModestMailOperationPrivate *priv;
1264 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1265 g_return_if_fail (TNY_IS_HEADER (header));
1267 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1268 folder = tny_header_get_folder (header);
1270 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1272 /* Get message from folder */
1274 helper = g_slice_new0 (GetMsgAsyncHelper);
1275 helper->mail_op = self;
1276 helper->user_callback = user_callback;
1277 helper->pending_ops = 1;
1278 helper->user_data = user_data;
1280 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1282 g_object_unref (G_OBJECT (folder));
1284 /* Set status failed and set an error */
1285 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1286 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1287 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1288 _("Error trying to get a message. No folder found for header"));
1293 get_msg_cb (TnyFolder *folder,
1299 GetMsgAsyncHelper *helper = NULL;
1300 ModestMailOperation *self = NULL;
1301 ModestMailOperationPrivate *priv = NULL;
1303 helper = (GetMsgAsyncHelper *) user_data;
1304 g_return_if_fail (helper != NULL);
1305 self = helper->mail_op;
1306 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1309 helper->pending_ops--;
1311 /* Check errors and cancel */
1313 priv->error = g_error_copy (*error);
1314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1318 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1320 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1321 _("Error trying to refresh the contents of %s"),
1322 tny_folder_get_name (folder));
1326 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1328 /* If user defined callback function was defined, call it */
1329 if (helper->user_callback) {
1330 helper->user_callback (self, NULL, msg, helper->user_data);
1335 if (helper->pending_ops == 0) {
1336 g_slice_free (GetMsgAsyncHelper, helper);
1338 /* Notify about operation end */
1339 modest_mail_operation_notify_end (self);
1344 get_msg_status_cb (GObject *obj,
1348 GetMsgAsyncHelper *helper = NULL;
1349 ModestMailOperation *self;
1350 ModestMailOperationPrivate *priv;
1351 ModestMailOperationState *state;
1353 g_return_if_fail (status != NULL);
1354 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1356 helper = (GetMsgAsyncHelper *) user_data;
1357 g_return_if_fail (helper != NULL);
1359 self = helper->mail_op;
1360 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1362 if ((status->position == 1) && (status->of_total == 100))
1368 state = modest_mail_operation_clone_state (self);
1369 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1370 g_slice_free (ModestMailOperationState, state);
1373 /****************************************************/
1375 ModestMailOperation *mail_op;
1377 GetMsgAsyncUserCallback user_callback;
1379 GDestroyNotify notify;
1383 GetMsgAsyncUserCallback user_callback;
1387 ModestMailOperation *mail_op;
1388 } NotifyGetMsgsInfo;
1392 * Used by get_msgs_full_thread to call the user_callback for each
1393 * message that has been read
1396 notify_get_msgs_full (gpointer data)
1398 NotifyGetMsgsInfo *info;
1400 info = (NotifyGetMsgsInfo *) data;
1402 /* Call the user callback */
1403 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1405 g_slice_free (NotifyGetMsgsInfo, info);
1411 * Used by get_msgs_full_thread to free al the thread resources and to
1412 * call the destroy function for the passed user_data
1415 get_msgs_full_destroyer (gpointer data)
1417 GetFullMsgsInfo *info;
1419 info = (GetFullMsgsInfo *) data;
1422 info->notify (info->user_data);
1425 g_object_unref (info->headers);
1426 g_slice_free (GetFullMsgsInfo, info);
1432 get_msgs_full_thread (gpointer thr_user_data)
1434 GetFullMsgsInfo *info;
1435 ModestMailOperationPrivate *priv = NULL;
1436 TnyIterator *iter = NULL;
1438 info = (GetFullMsgsInfo *) thr_user_data;
1439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1441 iter = tny_list_create_iterator (info->headers);
1442 while (!tny_iterator_is_done (iter)) {
1446 header = TNY_HEADER (tny_iterator_get_current (iter));
1447 folder = tny_header_get_folder (header);
1449 /* Get message from folder */
1452 /* The callback will call it per each header */
1453 msg = tny_folder_get_msg (folder, header, &(priv->error));
1456 ModestMailOperationState *state;
1461 /* notify progress */
1462 state = modest_mail_operation_clone_state (info->mail_op);
1463 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1464 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1465 pair, (GDestroyNotify) modest_pair_free);
1467 /* The callback is the responsible for
1468 freeing the message */
1469 if (info->user_callback) {
1470 NotifyGetMsgsInfo *info_notify;
1471 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1472 info_notify->user_callback = info->user_callback;
1473 info_notify->mail_op = info->mail_op;
1474 info_notify->header = g_object_ref (header);
1475 info_notify->msg = g_object_ref (msg);
1476 info_notify->user_data = info->user_data;
1477 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1478 notify_get_msgs_full,
1481 g_object_unref (msg);
1484 /* Set status failed and set an error */
1485 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1486 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1487 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1488 "Error trying to get a message. No folder found for header");
1490 g_object_unref (header);
1491 tny_iterator_next (iter);
1494 /* Notify about operation end */
1495 g_idle_add (notify_update_account_queue, info->mail_op);
1497 /* Free thread resources. Will be called after all previous idles */
1498 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1504 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1505 TnyList *header_list,
1506 GetMsgAsyncUserCallback user_callback,
1508 GDestroyNotify notify)
1511 ModestMailOperationPrivate *priv = NULL;
1512 GetFullMsgsInfo *info = NULL;
1513 gboolean size_ok = TRUE;
1515 GError *error = NULL;
1517 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1519 /* Init mail operation */
1520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1521 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1523 priv->total = tny_list_get_length(header_list);
1525 /* Get msg size limit */
1526 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1527 MODEST_CONF_MSG_SIZE_LIMIT,
1530 g_clear_error (&error);
1531 max_size = G_MAXINT;
1533 max_size = max_size * KB;
1536 /* Check message size limits. If there is only one message
1537 always retrieve it */
1538 if (tny_list_get_length (header_list) > 1) {
1541 iter = tny_list_create_iterator (header_list);
1542 while (!tny_iterator_is_done (iter) && size_ok) {
1543 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1544 if (tny_header_get_message_size (header) >= max_size)
1546 g_object_unref (header);
1547 tny_iterator_next (iter);
1549 g_object_unref (iter);
1553 /* Create the info */
1554 info = g_slice_new0 (GetFullMsgsInfo);
1555 info->mail_op = self;
1556 info->user_callback = user_callback;
1557 info->user_data = user_data;
1558 info->headers = g_object_ref (header_list);
1559 info->notify = notify;
1561 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1563 /* FIXME: the error msg is different for pop */
1564 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1565 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1566 _("emev_ni_ui_imap_msg_sizelimit_error"));
1567 /* Remove from queue and free resources */
1568 modest_mail_operation_notify_end (self);
1576 modest_mail_operation_remove_msg (ModestMailOperation *self,
1578 gboolean remove_to_trash)
1581 ModestMailOperationPrivate *priv;
1583 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1584 g_return_if_fail (TNY_IS_HEADER (header));
1586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1587 folder = tny_header_get_folder (header);
1589 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1591 /* Delete or move to trash */
1592 if (remove_to_trash) {
1593 TnyFolder *trash_folder;
1594 TnyStoreAccount *store_account;
1596 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1597 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1598 TNY_FOLDER_TYPE_TRASH);
1603 headers = tny_simple_list_new ();
1604 tny_list_append (headers, G_OBJECT (header));
1605 g_object_unref (header);
1608 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1609 g_object_unref (headers);
1610 /* g_object_unref (trash_folder); */
1612 ModestMailOperationPrivate *priv;
1614 /* Set status failed and set an error */
1615 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1616 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1617 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1618 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1619 _("Error trying to delete a message. Trash folder not found"));
1622 g_object_unref (G_OBJECT (store_account));
1624 tny_folder_remove_msg (folder, header, &(priv->error));
1626 tny_folder_sync(folder, TRUE, &(priv->error));
1631 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1633 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1636 g_object_unref (G_OBJECT (folder));
1638 /* Notify about operation end */
1639 modest_mail_operation_notify_end (self);
1643 transfer_msgs_status_cb (GObject *obj,
1647 XFerMsgAsyncHelper *helper = NULL;
1648 ModestMailOperation *self;
1649 ModestMailOperationPrivate *priv;
1650 ModestMailOperationState *state;
1653 g_return_if_fail (status != NULL);
1654 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1656 helper = (XFerMsgAsyncHelper *) user_data;
1657 g_return_if_fail (helper != NULL);
1659 self = helper->mail_op;
1660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1662 if ((status->position == 1) && (status->of_total == 100))
1665 priv->done = status->position;
1666 priv->total = status->of_total;
1668 state = modest_mail_operation_clone_state (self);
1669 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1670 g_slice_free (ModestMailOperationState, state);
1675 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1677 XFerMsgAsyncHelper *helper;
1678 ModestMailOperation *self;
1679 ModestMailOperationPrivate *priv;
1681 helper = (XFerMsgAsyncHelper *) user_data;
1682 self = helper->mail_op;
1684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1687 priv->error = g_error_copy (*err);
1689 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1690 } else if (cancelled) {
1691 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1692 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1693 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1694 _("Error trying to refresh the contents of %s"),
1695 tny_folder_get_name (folder));
1698 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1701 /* If user defined callback function was defined, call it */
1702 if (helper->user_callback) {
1703 helper->user_callback (priv->source, helper->user_data);
1707 g_object_unref (helper->headers);
1708 g_object_unref (helper->dest_folder);
1709 g_object_unref (helper->mail_op);
1710 g_slice_free (XFerMsgAsyncHelper, helper);
1711 g_object_unref (folder);
1713 /* Notify about operation end */
1714 modest_mail_operation_notify_end (self);
1718 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1721 gboolean delete_original,
1722 XferMsgsAsynUserCallback user_callback,
1725 ModestMailOperationPrivate *priv;
1727 TnyFolder *src_folder;
1728 XFerMsgAsyncHelper *helper;
1730 ModestTnyFolderRules rules;
1732 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1733 g_return_if_fail (TNY_IS_LIST (headers));
1734 g_return_if_fail (TNY_IS_FOLDER (folder));
1736 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1739 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1741 /* Apply folder rules */
1742 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1744 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1746 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1747 _("FIXME: folder does not accept msgs"));
1748 /* Notify the queue */
1749 modest_mail_operation_notify_end (self);
1753 /* Create the helper */
1754 helper = g_slice_new0 (XFerMsgAsyncHelper);
1755 helper->mail_op = g_object_ref(self);
1756 helper->dest_folder = g_object_ref(folder);
1757 helper->headers = g_object_ref(headers);
1758 helper->user_callback = user_callback;
1759 helper->user_data = user_data;
1761 /* Get source folder */
1762 iter = tny_list_create_iterator (headers);
1763 header = TNY_HEADER (tny_iterator_get_current (iter));
1764 src_folder = tny_header_get_folder (header);
1765 g_object_unref (header);
1766 g_object_unref (iter);
1768 /* Transfer messages */
1769 tny_folder_transfer_msgs_async (src_folder,
1774 transfer_msgs_status_cb,
1780 on_refresh_folder (TnyFolder *folder,
1785 ModestMailOperation *self;
1786 ModestMailOperationPrivate *priv;
1788 self = MODEST_MAIL_OPERATION (user_data);
1789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1792 priv->error = g_error_copy (*error);
1793 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1800 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1801 _("Error trying to refresh the contents of %s"),
1802 tny_folder_get_name (folder));
1806 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1810 g_object_unref (folder);
1812 /* Notify about operation end */
1813 modest_mail_operation_notify_end (self);
1817 on_refresh_folder_status_update (GObject *obj,
1821 ModestMailOperation *self;
1822 ModestMailOperationPrivate *priv;
1823 ModestMailOperationState *state;
1825 g_return_if_fail (status != NULL);
1826 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1828 self = MODEST_MAIL_OPERATION (user_data);
1829 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1831 priv->done = status->position;
1832 priv->total = status->of_total;
1834 state = modest_mail_operation_clone_state (self);
1835 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1836 g_slice_free (ModestMailOperationState, state);
1840 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1843 ModestMailOperationPrivate *priv;
1845 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1847 /* Pick a reference */
1848 g_object_ref (folder);
1850 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1852 /* Refresh the folder. TODO: tinymail could issue a status
1853 updates before the callback call then this could happen. We
1854 must review the design */
1855 tny_folder_refresh_async (folder,
1857 on_refresh_folder_status_update,
1863 * It's used by the mail operation queue to notify the observers
1864 * attached to that signal that the operation finished. We need to use
1865 * that because tinymail does not give us the progress of a given
1866 * operation when it finishes (it directly calls the operation
1870 modest_mail_operation_notify_end (ModestMailOperation *self)
1872 ModestMailOperationState *state;
1874 /* Notify the observers about the mail opertation end */
1875 state = modest_mail_operation_clone_state (self);
1876 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1877 g_slice_free (ModestMailOperationState, state);
1879 /* Notify the queue */
1880 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);