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 gpointer error_checking_user_data;
91 ModestMailOperationStatus status;
92 ModestMailOperationTypeOperation op_type;
95 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
96 MODEST_TYPE_MAIL_OPERATION, \
97 ModestMailOperationPrivate))
99 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
100 priv->status = new_status;\
103 typedef struct _GetMsgAsyncHelper {
104 ModestMailOperation *mail_op;
105 GetMsgAsyncUserCallback user_callback;
110 typedef struct _XFerMsgAsyncHelper
112 ModestMailOperation *mail_op;
114 TnyFolder *dest_folder;
115 XferMsgsAsynUserCallback user_callback;
117 } XFerMsgAsyncHelper;
120 static GObjectClass *parent_class = NULL;
122 static guint signals[NUM_SIGNALS] = {0};
125 modest_mail_operation_get_type (void)
127 static GType my_type = 0;
129 static const GTypeInfo my_info = {
130 sizeof(ModestMailOperationClass),
131 NULL, /* base init */
132 NULL, /* base finalize */
133 (GClassInitFunc) modest_mail_operation_class_init,
134 NULL, /* class finalize */
135 NULL, /* class data */
136 sizeof(ModestMailOperation),
138 (GInstanceInitFunc) modest_mail_operation_init,
141 my_type = g_type_register_static (G_TYPE_OBJECT,
142 "ModestMailOperation",
149 modest_mail_operation_class_init (ModestMailOperationClass *klass)
151 GObjectClass *gobject_class;
152 gobject_class = (GObjectClass*) klass;
154 parent_class = g_type_class_peek_parent (klass);
155 gobject_class->finalize = modest_mail_operation_finalize;
157 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
160 * ModestMailOperation::progress-changed
161 * @self: the #MailOperation that emits the signal
162 * @user_data: user data set when the signal handler was connected
164 * Emitted when the progress of a mail operation changes
166 signals[PROGRESS_CHANGED_SIGNAL] =
167 g_signal_new ("progress-changed",
168 G_TYPE_FROM_CLASS (gobject_class),
170 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
172 g_cclosure_marshal_VOID__POINTER,
173 G_TYPE_NONE, 1, G_TYPE_POINTER);
177 modest_mail_operation_init (ModestMailOperation *obj)
179 ModestMailOperationPrivate *priv;
181 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
183 priv->account = NULL;
184 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
185 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
190 priv->error_checking = NULL;
191 priv->error_checking_user_data = NULL;
195 modest_mail_operation_finalize (GObject *obj)
197 ModestMailOperationPrivate *priv;
199 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
202 g_error_free (priv->error);
206 g_object_unref (priv->source);
210 g_object_unref (priv->account);
211 priv->account = NULL;
215 G_OBJECT_CLASS(parent_class)->finalize (obj);
219 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
222 ModestMailOperation *obj;
223 ModestMailOperationPrivate *priv;
225 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
226 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
228 priv->op_type = op_type;
230 priv->source = g_object_ref(source);
236 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
238 ErrorCheckingUserCallback error_handler,
241 ModestMailOperation *obj;
242 ModestMailOperationPrivate *priv;
244 obj = modest_mail_operation_new (op_type, source);
245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
247 g_return_val_if_fail (error_handler != NULL, obj);
248 priv->error_checking = error_handler;
254 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
256 ModestMailOperationPrivate *priv;
258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
259 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
261 if (priv->error_checking != NULL)
262 priv->error_checking (self, priv->error_checking_user_data);
266 ModestMailOperationTypeOperation
267 modest_mail_operation_get_type_operation (ModestMailOperation *self)
269 ModestMailOperationPrivate *priv;
271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
273 return priv->op_type;
277 modest_mail_operation_is_mine (ModestMailOperation *self,
280 ModestMailOperationPrivate *priv;
282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
283 if (priv->source == NULL) return FALSE;
285 return priv->source == me;
289 modest_mail_operation_get_source (ModestMailOperation *self)
291 ModestMailOperationPrivate *priv;
293 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
295 return g_object_ref (priv->source);
298 ModestMailOperationStatus
299 modest_mail_operation_get_status (ModestMailOperation *self)
301 ModestMailOperationPrivate *priv;
303 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
304 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
305 MODEST_MAIL_OPERATION_STATUS_INVALID);
307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
312 modest_mail_operation_get_error (ModestMailOperation *self)
314 ModestMailOperationPrivate *priv;
316 g_return_val_if_fail (self, NULL);
317 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
324 modest_mail_operation_cancel (ModestMailOperation *self)
326 ModestMailOperationPrivate *priv;
328 if (!MODEST_IS_MAIL_OPERATION (self)) {
329 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
333 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
335 /* TODO: Tinymail does not support cancel operation */
336 /* tny_account_cancel (); */
339 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
341 /* Notify about operation end */
342 modest_mail_operation_notify_end (self);
348 modest_mail_operation_get_task_done (ModestMailOperation *self)
350 ModestMailOperationPrivate *priv;
352 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
359 modest_mail_operation_get_task_total (ModestMailOperation *self)
361 ModestMailOperationPrivate *priv;
363 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
370 modest_mail_operation_is_finished (ModestMailOperation *self)
372 ModestMailOperationPrivate *priv;
373 gboolean retval = FALSE;
375 if (!MODEST_IS_MAIL_OPERATION (self)) {
376 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
380 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
382 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
384 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
385 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
395 modest_mail_operation_get_id (ModestMailOperation *self)
397 ModestMailOperationPrivate *priv;
399 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
406 modest_mail_operation_set_id (ModestMailOperation *self,
409 ModestMailOperationPrivate *priv;
411 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
413 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
418 * Creates an image of the current state of a mail operation, the
419 * caller must free it
421 static ModestMailOperationState *
422 modest_mail_operation_clone_state (ModestMailOperation *self)
424 ModestMailOperationState *state;
425 ModestMailOperationPrivate *priv;
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
429 state = g_slice_new (ModestMailOperationState);
431 state->status = priv->status;
432 state->op_type = priv->op_type;
433 state->done = priv->done;
434 state->total = priv->total;
435 state->finished = modest_mail_operation_is_finished (self);
440 /* ******************************************************************* */
441 /* ************************** SEND ACTIONS ************************* */
442 /* ******************************************************************* */
445 modest_mail_operation_send_mail (ModestMailOperation *self,
446 TnyTransportAccount *transport_account,
449 TnySendQueue *send_queue = NULL;
450 ModestMailOperationPrivate *priv;
452 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
453 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
454 g_return_if_fail (TNY_IS_MSG (msg));
456 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
458 /* Get account and set it into mail_operation */
459 priv->account = g_object_ref (transport_account);
461 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
462 if (!TNY_IS_SEND_QUEUE(send_queue)) {
463 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
464 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
465 "modest: could not find send queue for account\n");
467 tny_send_queue_add (send_queue, msg, &(priv->error));
470 /* Notify about operation end */
471 modest_mail_operation_notify_end (self);
475 modest_mail_operation_send_new_mail (ModestMailOperation *self,
476 TnyTransportAccount *transport_account,
477 const gchar *from, const gchar *to,
478 const gchar *cc, const gchar *bcc,
479 const gchar *subject, const gchar *plain_body,
480 const gchar *html_body,
481 const GList *attachments_list,
482 TnyHeaderFlags priority_flags)
484 TnyMsg *new_msg = NULL;
485 ModestMailOperationPrivate *priv = 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 /* Get account and set it into mail_operation */
493 priv->account = g_object_ref (transport_account);
495 /* Check parametters */
497 /* Set status failed and set an error */
498 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
499 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
500 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
501 _("Error trying to send a mail. You need to set at least one recipient"));
505 if (html_body == NULL) {
506 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
508 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
511 g_printerr ("modest: failed to create a new msg\n");
515 /* TODO: add priority handling. It's received in the priority_flags operator, and
516 it should have effect in the sending operation */
518 /* Call mail operation */
519 modest_mail_operation_send_mail (self, transport_account, new_msg);
522 g_object_unref (G_OBJECT (new_msg));
526 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
527 TnyTransportAccount *transport_account,
528 const gchar *from, const gchar *to,
529 const gchar *cc, const gchar *bcc,
530 const gchar *subject, const gchar *plain_body,
531 const gchar *html_body,
532 const GList *attachments_list,
533 TnyHeaderFlags priority_flags)
536 TnyFolder *folder = NULL;
537 ModestMailOperationPrivate *priv = NULL;
539 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
540 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
542 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
544 /* Get account and set it into mail_operation */
545 priv->account = g_object_ref (transport_account);
547 if (html_body == NULL) {
548 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
550 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
553 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
554 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
555 "modest: failed to create a new msg\n");
559 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
561 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
562 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
563 "modest: failed to create a new msg\n");
567 tny_folder_add_msg (folder, msg, &(priv->error));
573 g_object_unref (G_OBJECT(msg));
575 g_object_unref (G_OBJECT(folder));
577 modest_mail_operation_notify_end (self);
582 ModestMailOperation *mail_op;
583 TnyStoreAccount *account;
584 TnyTransportAccount *transport_account;
587 gchar *retrieve_type;
590 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
591 /* We use this folder observer to track the headers that have been
592 * added to a folder */
595 TnyList *new_headers;
596 } InternalFolderObserver;
600 } InternalFolderObserverClass;
602 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
604 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
605 internal_folder_observer,
607 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
611 foreach_add_item (gpointer header, gpointer user_data)
613 tny_list_prepend (TNY_LIST (user_data),
614 g_object_ref (G_OBJECT (header)));
617 /* This is the method that looks for new messages in a folder */
619 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
621 TnyFolderChangeChanged changed;
623 changed = tny_folder_change_get_changed (change);
625 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
628 /* Get added headers */
629 list = tny_simple_list_new ();
630 tny_folder_change_get_added_headers (change, list);
632 /* Add them to the folder observer */
633 tny_list_foreach (list, foreach_add_item,
634 ((InternalFolderObserver *)self)->new_headers);
636 g_object_unref (G_OBJECT (list));
641 internal_folder_observer_init (InternalFolderObserver *self)
643 self->new_headers = tny_simple_list_new ();
646 internal_folder_observer_finalize (GObject *object)
648 InternalFolderObserver *self;
650 self = (InternalFolderObserver *) object;
651 g_object_unref (self->new_headers);
653 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
656 tny_folder_observer_init (TnyFolderObserverIface *iface)
658 iface->update_func = internal_folder_observer_update;
661 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
663 GObjectClass *object_class;
665 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
666 object_class = (GObjectClass*) klass;
667 object_class->finalize = internal_folder_observer_finalize;
673 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
676 TnyList *folders = tny_simple_list_new ();
678 tny_folder_store_get_folders (store, folders, query, NULL);
679 iter = tny_list_create_iterator (folders);
681 while (!tny_iterator_is_done (iter)) {
683 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
685 tny_list_prepend (all_folders, G_OBJECT (folder));
686 recurse_folders (folder, query, all_folders);
687 g_object_unref (G_OBJECT (folder));
689 tny_iterator_next (iter);
691 g_object_unref (G_OBJECT (iter));
692 g_object_unref (G_OBJECT (folders));
696 * Issues the "progress-changed" signal. The timer won't be removed,
697 * so you must call g_source_remove to stop the signal emission
700 idle_notify_progress (gpointer data)
702 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
703 ModestMailOperationState *state;
705 state = modest_mail_operation_clone_state (mail_op);
706 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
707 g_slice_free (ModestMailOperationState, state);
713 * Issues the "progress-changed" signal and removes the timer. It uses
714 * a lock to ensure that the progress information of the mail
715 * operation is not modified while there are notifications pending
718 idle_notify_progress_once (gpointer data)
722 pair = (ModestPair *) data;
724 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
726 /* Free the state and the reference to the mail operation */
727 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
728 g_object_unref (pair->first);
734 * Used by update_account_thread to notify the queue from the main
735 * loop. We call it inside an idle call to achieve that
738 notify_update_account_queue (gpointer data)
740 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
742 modest_mail_operation_notify_end (mail_op);
743 g_object_unref (mail_op);
749 compare_headers_by_date (gconstpointer a,
752 TnyHeader **header1, **header2;
755 header1 = (TnyHeader **) a;
756 header2 = (TnyHeader **) b;
758 sent1 = tny_header_get_date_sent (*header1);
759 sent2 = tny_header_get_date_sent (*header2);
761 /* We want the most recent ones (greater time_t) at the
770 update_account_thread (gpointer thr_user_data)
772 UpdateAccountInfo *info;
773 TnyList *all_folders = NULL;
774 GPtrArray *new_headers;
775 TnyIterator *iter = NULL;
776 TnyFolderStoreQuery *query = NULL;
777 ModestMailOperationPrivate *priv;
779 info = (UpdateAccountInfo *) thr_user_data;
780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
782 /* Get account and set it into mail_operation */
783 priv->account = g_object_ref (info->account);
785 /* Get all the folders We can do it synchronously because
786 we're already running in a different thread than the UI */
787 all_folders = tny_simple_list_new ();
788 query = tny_folder_store_query_new ();
789 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
790 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
795 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
799 iter = tny_list_create_iterator (all_folders);
800 while (!tny_iterator_is_done (iter)) {
801 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
803 recurse_folders (folder, query, all_folders);
804 tny_iterator_next (iter);
806 g_object_unref (G_OBJECT (iter));
808 /* Update status and notify. We need to call the notification
809 with a source functopm in order to call it from the main
810 loop. We need that in order not to get into trouble with
811 Gtk+. We use a timeout in order to provide more status
812 information, because the sync tinymail call does not
813 provide it for the moment */
814 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
816 /* Refresh folders */
817 new_headers = g_ptr_array_new ();
818 iter = tny_list_create_iterator (all_folders);
819 while (!tny_iterator_is_done (iter) && !priv->error) {
821 InternalFolderObserver *observer;
822 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
824 /* Refresh the folder */
825 observer = g_object_new (internal_folder_observer_get_type (), NULL);
826 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
827 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
829 /* If the retrieve type is headers only do nothing more */
830 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
831 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
834 iter = tny_list_create_iterator (observer->new_headers);
835 while (!tny_iterator_is_done (iter)) {
836 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
837 /* Apply per-message size limits */
838 if (tny_header_get_message_size (header) < info->max_size)
839 g_ptr_array_add (new_headers, g_object_ref (header));
841 g_object_unref (header);
842 tny_iterator_next (iter);
844 g_object_unref (iter);
846 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
847 g_object_unref (observer);
850 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
852 g_object_unref (G_OBJECT (folder));
853 tny_iterator_next (iter);
855 g_object_unref (G_OBJECT (iter));
856 g_source_remove (timeout);
858 if (new_headers->len > 0) {
862 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
864 /* Apply message count limit */
865 /* TODO if the number of messages exceeds the maximum, ask the
866 user to download them all */
868 priv->total = MIN (new_headers->len, info->retrieve_limit);
869 while ((msg_num < priv->total)) {
871 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
872 TnyFolder *folder = tny_header_get_folder (header);
873 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
874 ModestMailOperationState *state;
878 /* We can not just use the mail operation because the
879 values of done and total could change before the
881 state = modest_mail_operation_clone_state (info->mail_op);
882 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
883 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
884 pair, (GDestroyNotify) modest_pair_free);
886 g_object_unref (msg);
887 g_object_unref (folder);
891 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
892 g_ptr_array_free (new_headers, FALSE);
896 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
899 if (priv->account != NULL)
900 g_object_unref (priv->account);
901 priv->account = g_object_ref (info->transport_account);
903 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
904 (info->transport_account);
906 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
907 modest_tny_send_queue_try_to_send (send_queue);
908 g_source_remove (timeout);
910 g_object_unref (G_OBJECT(send_queue));
912 /* Check if the operation was a success */
914 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
916 /* Update the last updated key */
917 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
918 tny_account_get_id (TNY_ACCOUNT (info->account)),
919 MODEST_ACCOUNT_LAST_UPDATED,
925 /* Notify about operation end. Note that the info could be
926 freed before this idle happens, but the mail operation will
928 g_idle_add (notify_update_account_queue, info->mail_op);
931 g_object_unref (query);
932 g_object_unref (all_folders);
933 g_object_unref (info->account);
934 g_object_unref (info->transport_account);
935 g_free (info->retrieve_type);
936 g_slice_free (UpdateAccountInfo, info);
942 modest_mail_operation_update_account (ModestMailOperation *self,
943 const gchar *account_name)
946 UpdateAccountInfo *info;
947 ModestMailOperationPrivate *priv;
948 ModestAccountMgr *mgr;
949 TnyStoreAccount *modest_account;
950 TnyTransportAccount *transport_account;
952 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
953 g_return_val_if_fail (account_name, FALSE);
955 /* Init mail operation. Set total and done to 0, and do not
956 update them, this way the progress objects will know that
957 we have no clue about the number of the objects */
958 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
961 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
963 /* Get the Modest account */
964 modest_account = (TnyStoreAccount *)
965 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
967 TNY_ACCOUNT_TYPE_STORE);
969 if (!modest_account) {
970 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
971 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
972 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
973 "cannot get tny store account for %s\n", account_name);
974 modest_mail_operation_notify_end (self);
978 /* Get the transport account, we can not do it in the thread
979 due to some problems with dbus */
980 transport_account = (TnyTransportAccount *)
981 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
983 if (!transport_account) {
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
986 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
987 "cannot get tny transport account for %s\n", account_name);
988 modest_mail_operation_notify_end (self);
992 /* Create the helper object */
993 info = g_slice_new (UpdateAccountInfo);
994 info->mail_op = self;
995 info->account = modest_account;
996 info->transport_account = transport_account;
998 /* Get the message size limit */
999 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1000 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1001 if (info->max_size == 0)
1002 info->max_size = G_MAXINT;
1004 info->max_size = info->max_size * KB;
1006 /* Get per-account retrieval type */
1007 mgr = modest_runtime_get_account_mgr ();
1008 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1009 MODEST_ACCOUNT_RETRIEVE, FALSE);
1011 /* Get per-account message amount retrieval limit */
1012 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1013 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1014 if (info->retrieve_limit == 0)
1015 info->retrieve_limit = G_MAXINT;
1017 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1022 /* ******************************************************************* */
1023 /* ************************** STORE ACTIONS ************************* */
1024 /* ******************************************************************* */
1028 modest_mail_operation_create_folder (ModestMailOperation *self,
1029 TnyFolderStore *parent,
1032 ModestTnyFolderRules rules;
1033 ModestMailOperationPrivate *priv;
1034 TnyFolder *new_folder = NULL;
1035 gboolean can_create = FALSE;
1037 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1038 g_return_val_if_fail (name, NULL);
1040 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1042 /* Get account and set it into mail_operation */
1043 priv->account = tny_folder_get_account (TNY_FOLDER(parent));
1046 if (!TNY_IS_FOLDER (parent)) {
1047 /* Set status failed and set an error */
1048 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1049 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1050 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1051 _("mail_in_ui_folder_create_error"));
1053 /* Check folder rules */
1054 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1055 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1056 /* Set status failed and set an error */
1057 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1059 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1060 _("mail_in_ui_folder_create_error"));
1067 /* Create the folder */
1068 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1069 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1072 /* Notify about operation end */
1073 modest_mail_operation_notify_end (self);
1079 modest_mail_operation_remove_folder (ModestMailOperation *self,
1081 gboolean remove_to_trash)
1083 TnyAccount *account;
1084 ModestMailOperationPrivate *priv;
1085 ModestTnyFolderRules rules;
1087 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1088 g_return_if_fail (TNY_IS_FOLDER (folder));
1090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1092 /* Check folder rules */
1093 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1094 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1095 /* Set status failed and set an error */
1096 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1097 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1098 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1099 _("mail_in_ui_folder_delete_error"));
1103 /* Get the account */
1104 account = tny_folder_get_account (folder);
1105 priv->account = g_object_ref(account);
1107 /* Delete folder or move to trash */
1108 if (remove_to_trash) {
1109 TnyFolder *trash_folder = NULL;
1110 trash_folder = modest_tny_account_get_special_folder (account,
1111 TNY_FOLDER_TYPE_TRASH);
1112 /* TODO: error_handling */
1113 modest_mail_operation_xfer_folder (self, folder,
1114 TNY_FOLDER_STORE (trash_folder), TRUE);
1116 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1118 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1119 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1122 g_object_unref (G_OBJECT (parent));
1124 g_object_unref (G_OBJECT (account));
1127 /* Notify about operation end */
1128 modest_mail_operation_notify_end (self);
1132 transfer_folder_status_cb (GObject *obj,
1136 ModestMailOperation *self;
1137 ModestMailOperationPrivate *priv;
1138 ModestMailOperationState *state;
1140 g_return_if_fail (status != NULL);
1141 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1143 self = MODEST_MAIL_OPERATION (user_data);
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,
1160 TnyFolderStore *into,
1162 TnyFolder *new_folder, GError **err,
1165 ModestMailOperation *self = NULL;
1166 ModestMailOperationPrivate *priv = NULL;
1168 self = MODEST_MAIL_OPERATION (user_data);
1170 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1173 priv->error = g_error_copy (*err);
1175 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1176 } else if (cancelled) {
1177 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1178 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1179 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1180 _("Transference of %s was cancelled."),
1181 tny_folder_get_name (folder));
1184 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1188 g_object_unref (folder);
1189 g_object_unref (into);
1190 if (new_folder != NULL)
1191 g_object_unref (new_folder);
1193 /* Notify about operation end */
1194 modest_mail_operation_notify_end (self);
1198 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1200 TnyFolderStore *parent,
1201 gboolean delete_original)
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 (folder));
1208 g_return_if_fail (TNY_IS_FOLDER (parent));
1210 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1212 /* Get account and set it into mail_operation */
1213 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1214 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
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 if (!TNY_IS_FOLDER_STORE (parent)) {
1224 /* The moveable restriction is applied also to copy operation */
1225 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1226 /* Set status failed and set an error */
1227 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1229 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1230 _("mail_in_ui_folder_move_target_error"));
1232 /* Notify the queue */
1233 modest_mail_operation_notify_end (self);
1234 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1235 /* Set status failed and set an error */
1236 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1237 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1238 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1239 _("FIXME: parent folder does not accept new folders"));
1241 /* Notify the queue */
1242 modest_mail_operation_notify_end (self);
1244 /* Pick references for async calls */
1245 g_object_ref (folder);
1246 g_object_ref (parent);
1248 /* Move/Copy folder */
1249 tny_folder_copy_async (folder,
1251 tny_folder_get_name (folder),
1254 transfer_folder_status_cb,
1260 modest_mail_operation_rename_folder (ModestMailOperation *self,
1264 ModestMailOperationPrivate *priv;
1265 ModestTnyFolderRules rules;
1267 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1268 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1269 g_return_if_fail (name);
1271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1273 /* Get account and set it into mail_operation */
1274 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1276 /* Check folder rules */
1277 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1278 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1279 /* Set status failed and set an error */
1280 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1281 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1282 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1283 _("FIXME: unable to rename"));
1285 /* Notify about operation end */
1286 modest_mail_operation_notify_end (self);
1288 /* Rename. Camel handles folder subscription/unsubscription */
1289 TnyFolderStore *into;
1291 into = tny_folder_get_folder_store (folder);
1292 tny_folder_copy_async (folder, into, name, TRUE,
1294 transfer_folder_status_cb,
1297 g_object_unref (into);
1302 /* ******************************************************************* */
1303 /* ************************** MSG ACTIONS ************************* */
1304 /* ******************************************************************* */
1306 void modest_mail_operation_get_msg (ModestMailOperation *self,
1308 GetMsgAsyncUserCallback user_callback,
1311 GetMsgAsyncHelper *helper = NULL;
1313 ModestMailOperationPrivate *priv;
1315 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1316 g_return_if_fail (TNY_IS_HEADER (header));
1318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1319 folder = tny_header_get_folder (header);
1321 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1323 /* Get message from folder */
1325 /* Get account and set it into mail_operation */
1326 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1328 helper = g_slice_new0 (GetMsgAsyncHelper);
1329 helper->mail_op = self;
1330 helper->user_callback = user_callback;
1331 helper->pending_ops = 1;
1332 helper->user_data = user_data;
1334 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1336 g_object_unref (G_OBJECT (folder));
1338 /* Set status failed and set an error */
1339 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1340 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1341 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1342 _("Error trying to get a message. No folder found for header"));
1344 /* Notify the queue */
1345 modest_mail_operation_notify_end (self);
1350 get_msg_cb (TnyFolder *folder,
1356 GetMsgAsyncHelper *helper = NULL;
1357 ModestMailOperation *self = NULL;
1358 ModestMailOperationPrivate *priv = NULL;
1360 helper = (GetMsgAsyncHelper *) user_data;
1361 g_return_if_fail (helper != NULL);
1362 self = helper->mail_op;
1363 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1366 helper->pending_ops--;
1368 /* Check errors and cancel */
1370 priv->error = g_error_copy (*error);
1371 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1376 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1377 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1378 _("Error trying to refresh the contents of %s"),
1379 tny_folder_get_name (folder));
1383 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1385 /* If user defined callback function was defined, call it */
1386 if (helper->user_callback) {
1387 helper->user_callback (self, NULL, msg, helper->user_data);
1392 if (helper->pending_ops == 0) {
1393 g_slice_free (GetMsgAsyncHelper, helper);
1395 /* Notify about operation end */
1396 modest_mail_operation_notify_end (self);
1401 get_msg_status_cb (GObject *obj,
1405 GetMsgAsyncHelper *helper = NULL;
1406 ModestMailOperation *self;
1407 ModestMailOperationPrivate *priv;
1408 ModestMailOperationState *state;
1410 g_return_if_fail (status != NULL);
1411 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1413 helper = (GetMsgAsyncHelper *) user_data;
1414 g_return_if_fail (helper != NULL);
1416 self = helper->mail_op;
1417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1419 if ((status->position == 1) && (status->of_total == 100))
1425 state = modest_mail_operation_clone_state (self);
1426 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1427 g_slice_free (ModestMailOperationState, state);
1430 /****************************************************/
1432 ModestMailOperation *mail_op;
1434 GetMsgAsyncUserCallback user_callback;
1436 GDestroyNotify notify;
1440 GetMsgAsyncUserCallback user_callback;
1444 ModestMailOperation *mail_op;
1445 } NotifyGetMsgsInfo;
1449 * Used by get_msgs_full_thread to call the user_callback for each
1450 * message that has been read
1453 notify_get_msgs_full (gpointer data)
1455 NotifyGetMsgsInfo *info;
1457 info = (NotifyGetMsgsInfo *) data;
1459 /* Call the user callback */
1460 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1462 g_slice_free (NotifyGetMsgsInfo, info);
1468 * Used by get_msgs_full_thread to free al the thread resources and to
1469 * call the destroy function for the passed user_data
1472 get_msgs_full_destroyer (gpointer data)
1474 GetFullMsgsInfo *info;
1476 info = (GetFullMsgsInfo *) data;
1479 info->notify (info->user_data);
1482 g_object_unref (info->headers);
1483 g_slice_free (GetFullMsgsInfo, info);
1489 get_msgs_full_thread (gpointer thr_user_data)
1491 GetFullMsgsInfo *info;
1492 ModestMailOperationPrivate *priv = NULL;
1493 TnyIterator *iter = NULL;
1495 info = (GetFullMsgsInfo *) thr_user_data;
1496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1498 iter = tny_list_create_iterator (info->headers);
1499 while (!tny_iterator_is_done (iter)) {
1503 header = TNY_HEADER (tny_iterator_get_current (iter));
1504 folder = tny_header_get_folder (header);
1506 /* Get message from folder */
1509 /* The callback will call it per each header */
1510 msg = tny_folder_get_msg (folder, header, &(priv->error));
1513 ModestMailOperationState *state;
1518 /* notify progress */
1519 state = modest_mail_operation_clone_state (info->mail_op);
1520 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1521 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1522 pair, (GDestroyNotify) modest_pair_free);
1524 /* The callback is the responsible for
1525 freeing the message */
1526 if (info->user_callback) {
1527 NotifyGetMsgsInfo *info_notify;
1528 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1529 info_notify->user_callback = info->user_callback;
1530 info_notify->mail_op = info->mail_op;
1531 info_notify->header = g_object_ref (header);
1532 info_notify->msg = g_object_ref (msg);
1533 info_notify->user_data = info->user_data;
1534 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1535 notify_get_msgs_full,
1538 g_object_unref (msg);
1541 /* Set status failed and set an error */
1542 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1543 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1544 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1545 "Error trying to get a message. No folder found for header");
1547 g_object_unref (header);
1548 tny_iterator_next (iter);
1551 /* Set operation status */
1552 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1553 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1555 /* Notify about operation end */
1556 g_idle_add (notify_update_account_queue, info->mail_op);
1558 /* Free thread resources. Will be called after all previous idles */
1559 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1565 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1566 TnyList *header_list,
1567 GetMsgAsyncUserCallback user_callback,
1569 GDestroyNotify notify)
1571 TnyHeader *header = NULL;
1572 TnyFolder *folder = NULL;
1574 ModestMailOperationPrivate *priv = NULL;
1575 GetFullMsgsInfo *info = NULL;
1576 gboolean size_ok = TRUE;
1578 TnyIterator *iter = NULL;
1580 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1582 /* Init mail operation */
1583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1584 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1586 priv->total = tny_list_get_length(header_list);
1588 /* Get account and set it into mail_operation */
1589 if (tny_list_get_length (header_list) > 1) {
1590 iter = tny_list_create_iterator (header_list);
1591 header = TNY_HEADER (tny_iterator_get_current (iter));
1592 folder = tny_header_get_folder (header);
1593 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1594 g_object_unref (header);
1595 g_object_unref (folder);
1598 /* Get msg size limit */
1599 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1600 MODEST_CONF_MSG_SIZE_LIMIT,
1603 g_clear_error (&(priv->error));
1604 max_size = G_MAXINT;
1606 max_size = max_size * KB;
1609 /* Check message size limits. If there is only one message
1610 always retrieve it */
1612 while (!tny_iterator_is_done (iter) && size_ok) {
1613 header = TNY_HEADER (tny_iterator_get_current (iter));
1614 if (tny_header_get_message_size (header) >= max_size)
1616 g_object_unref (header);
1617 tny_iterator_next (iter);
1619 g_object_unref (iter);
1623 /* Create the info */
1624 info = g_slice_new0 (GetFullMsgsInfo);
1625 info->mail_op = self;
1626 info->user_callback = user_callback;
1627 info->user_data = user_data;
1628 info->headers = g_object_ref (header_list);
1629 info->notify = notify;
1631 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1633 /* Set status failed and set an error */
1634 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1635 /* FIXME: the error msg is different for pop */
1636 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1637 MODEST_MAIL_OPERATION_ERROR_SIZE_LIMIT,
1638 _("emev_ni_ui_imap_msg_size_exceed_error"));
1639 /* Remove from queue and free resources */
1640 modest_mail_operation_notify_end (self);
1648 modest_mail_operation_remove_msg (ModestMailOperation *self,
1650 gboolean remove_to_trash)
1653 ModestMailOperationPrivate *priv;
1655 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1656 g_return_if_fail (TNY_IS_HEADER (header));
1658 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1659 folder = tny_header_get_folder (header);
1661 /* Get account and set it into mail_operation */
1662 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1664 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1666 /* Delete or move to trash */
1667 if (remove_to_trash) {
1668 TnyFolder *trash_folder;
1669 TnyStoreAccount *store_account;
1671 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1672 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1673 TNY_FOLDER_TYPE_TRASH);
1678 headers = tny_simple_list_new ();
1679 tny_list_append (headers, G_OBJECT (header));
1680 g_object_unref (header);
1683 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1684 g_object_unref (headers);
1685 /* g_object_unref (trash_folder); */
1687 ModestMailOperationPrivate *priv;
1689 /* Set status failed and set an error */
1690 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1691 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1692 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1693 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1694 _("Error trying to delete a message. Trash folder not found"));
1697 g_object_unref (G_OBJECT (store_account));
1699 tny_folder_remove_msg (folder, header, &(priv->error));
1701 tny_folder_sync(folder, TRUE, &(priv->error));
1706 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1708 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1711 g_object_unref (G_OBJECT (folder));
1713 /* Notify about operation end */
1714 modest_mail_operation_notify_end (self);
1718 transfer_msgs_status_cb (GObject *obj,
1722 XFerMsgAsyncHelper *helper = NULL;
1723 ModestMailOperation *self;
1724 ModestMailOperationPrivate *priv;
1725 ModestMailOperationState *state;
1728 g_return_if_fail (status != NULL);
1729 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1731 helper = (XFerMsgAsyncHelper *) user_data;
1732 g_return_if_fail (helper != NULL);
1734 self = helper->mail_op;
1735 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1737 if ((status->position == 1) && (status->of_total == 100))
1740 priv->done = status->position;
1741 priv->total = status->of_total;
1743 state = modest_mail_operation_clone_state (self);
1744 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1745 g_slice_free (ModestMailOperationState, state);
1750 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1752 XFerMsgAsyncHelper *helper;
1753 ModestMailOperation *self;
1754 ModestMailOperationPrivate *priv;
1756 helper = (XFerMsgAsyncHelper *) user_data;
1757 self = helper->mail_op;
1759 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1762 priv->error = g_error_copy (*err);
1764 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1765 } else if (cancelled) {
1766 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1767 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1768 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1769 _("Error trying to refresh the contents of %s"),
1770 tny_folder_get_name (folder));
1773 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1776 /* If user defined callback function was defined, call it */
1777 if (helper->user_callback) {
1778 helper->user_callback (priv->source, helper->user_data);
1782 g_object_unref (helper->headers);
1783 g_object_unref (helper->dest_folder);
1784 g_object_unref (helper->mail_op);
1785 g_slice_free (XFerMsgAsyncHelper, helper);
1786 g_object_unref (folder);
1788 /* Notify about operation end */
1789 modest_mail_operation_notify_end (self);
1793 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1796 gboolean delete_original,
1797 XferMsgsAsynUserCallback user_callback,
1800 ModestMailOperationPrivate *priv;
1802 TnyFolder *src_folder;
1803 XFerMsgAsyncHelper *helper;
1805 ModestTnyFolderRules rules;
1807 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1808 g_return_if_fail (TNY_IS_LIST (headers));
1809 g_return_if_fail (TNY_IS_FOLDER (folder));
1811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1814 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1816 /* Apply folder rules */
1817 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1819 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1820 /* Set status failed and set an error */
1821 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1822 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1823 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1824 _("FIXME: folder does not accept msgs"));
1825 /* Notify the queue */
1826 modest_mail_operation_notify_end (self);
1830 /* Create the helper */
1831 helper = g_slice_new0 (XFerMsgAsyncHelper);
1832 helper->mail_op = g_object_ref(self);
1833 helper->dest_folder = g_object_ref(folder);
1834 helper->headers = g_object_ref(headers);
1835 helper->user_callback = user_callback;
1836 helper->user_data = user_data;
1838 /* Get source folder */
1839 iter = tny_list_create_iterator (headers);
1840 header = TNY_HEADER (tny_iterator_get_current (iter));
1841 src_folder = tny_header_get_folder (header);
1842 g_object_unref (header);
1843 g_object_unref (iter);
1845 /* Get account and set it into mail_operation */
1846 priv->account = tny_folder_get_account (src_folder);
1848 /* Transfer messages */
1849 tny_folder_transfer_msgs_async (src_folder,
1854 transfer_msgs_status_cb,
1860 on_refresh_folder (TnyFolder *folder,
1865 ModestMailOperation *self;
1866 ModestMailOperationPrivate *priv;
1868 self = MODEST_MAIL_OPERATION (user_data);
1869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1872 priv->error = g_error_copy (*error);
1873 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1878 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1879 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1880 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1881 _("Error trying to refresh the contents of %s"),
1882 tny_folder_get_name (folder));
1886 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1890 g_object_unref (folder);
1892 /* Notify about operation end */
1893 modest_mail_operation_notify_end (self);
1897 on_refresh_folder_status_update (GObject *obj,
1901 ModestMailOperation *self;
1902 ModestMailOperationPrivate *priv;
1903 ModestMailOperationState *state;
1905 g_return_if_fail (status != NULL);
1906 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1908 self = MODEST_MAIL_OPERATION (user_data);
1909 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1911 priv->done = status->position;
1912 priv->total = status->of_total;
1914 state = modest_mail_operation_clone_state (self);
1915 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1916 g_slice_free (ModestMailOperationState, state);
1920 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1923 ModestMailOperationPrivate *priv;
1925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1927 /* Pick a reference */
1928 g_object_ref (folder);
1930 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1932 /* Get account and set it into mail_operation */
1933 priv->account = tny_folder_get_account (folder);
1935 /* Refresh the folder. TODO: tinymail could issue a status
1936 updates before the callback call then this could happen. We
1937 must review the design */
1938 tny_folder_refresh_async (folder,
1940 on_refresh_folder_status_update,
1946 * It's used by the mail operation queue to notify the observers
1947 * attached to that signal that the operation finished. We need to use
1948 * that because tinymail does not give us the progress of a given
1949 * operation when it finishes (it directly calls the operation
1953 modest_mail_operation_notify_end (ModestMailOperation *self)
1955 ModestMailOperationState *state;
1957 /* Notify the observers about the mail opertation end */
1958 state = modest_mail_operation_clone_state (self);
1959 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1960 g_slice_free (ModestMailOperationState, state);
1962 /* Notify the queue */
1963 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);