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_printerr ("modest: could not find send queue for account\n");
466 tny_send_queue_add (send_queue, msg, &err);
468 g_printerr ("modest: error adding msg to send queue: %s\n",
472 /* g_message ("modest: message added to send queue"); */
476 /* Notify about operation end */
477 modest_mail_operation_notify_end (self);
481 modest_mail_operation_send_new_mail (ModestMailOperation *self,
482 TnyTransportAccount *transport_account,
483 const gchar *from, const gchar *to,
484 const gchar *cc, const gchar *bcc,
485 const gchar *subject, const gchar *plain_body,
486 const gchar *html_body,
487 const GList *attachments_list,
488 TnyHeaderFlags priority_flags)
490 TnyMsg *new_msg = NULL;
491 ModestMailOperationPrivate *priv = NULL;
493 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
494 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
498 /* Get account and set it into mail_operation */
499 priv->account = g_object_ref (transport_account);
501 /* Check parametters */
503 /* Set status failed and set an error */
504 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
505 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
506 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
507 _("Error trying to send a mail. You need to set at least one recipient"));
511 if (html_body == NULL) {
512 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
514 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
517 g_printerr ("modest: failed to create a new msg\n");
521 /* TODO: add priority handling. It's received in the priority_flags operator, and
522 it should have effect in the sending operation */
524 /* Call mail operation */
525 modest_mail_operation_send_mail (self, transport_account, new_msg);
528 g_object_unref (G_OBJECT (new_msg));
532 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
533 TnyTransportAccount *transport_account,
534 const gchar *from, const gchar *to,
535 const gchar *cc, const gchar *bcc,
536 const gchar *subject, const gchar *plain_body,
537 const gchar *html_body,
538 const GList *attachments_list,
539 TnyHeaderFlags priority_flags)
542 TnyFolder *folder = NULL;
543 ModestMailOperationPrivate *priv = NULL;
546 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
547 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
551 /* Get account and set it into mail_operation */
552 priv->account = g_object_ref (transport_account);
554 if (html_body == NULL) {
555 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
557 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
560 g_printerr ("modest: failed to create a new msg\n");
564 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
566 g_printerr ("modest: failed to find Drafts folder\n");
570 tny_folder_add_msg (folder, msg, &err);
572 g_printerr ("modest: error adding msg to Drafts folder: %s",
578 modest_mail_operation_notify_end (self);
583 g_object_unref (G_OBJECT(msg));
585 g_object_unref (G_OBJECT(folder));
590 ModestMailOperation *mail_op;
591 TnyStoreAccount *account;
592 TnyTransportAccount *transport_account;
595 gchar *retrieve_type;
598 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
599 /* We use this folder observer to track the headers that have been
600 * added to a folder */
603 TnyList *new_headers;
604 } InternalFolderObserver;
608 } InternalFolderObserverClass;
610 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
612 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
613 internal_folder_observer,
615 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
619 foreach_add_item (gpointer header, gpointer user_data)
621 tny_list_prepend (TNY_LIST (user_data),
622 g_object_ref (G_OBJECT (header)));
625 /* This is the method that looks for new messages in a folder */
627 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
629 TnyFolderChangeChanged changed;
631 changed = tny_folder_change_get_changed (change);
633 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
636 /* Get added headers */
637 list = tny_simple_list_new ();
638 tny_folder_change_get_added_headers (change, list);
640 /* Add them to the folder observer */
641 tny_list_foreach (list, foreach_add_item,
642 ((InternalFolderObserver *)self)->new_headers);
644 g_object_unref (G_OBJECT (list));
649 internal_folder_observer_init (InternalFolderObserver *self)
651 self->new_headers = tny_simple_list_new ();
654 internal_folder_observer_finalize (GObject *object)
656 InternalFolderObserver *self;
658 self = (InternalFolderObserver *) object;
659 g_object_unref (self->new_headers);
661 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
664 tny_folder_observer_init (TnyFolderObserverIface *iface)
666 iface->update_func = internal_folder_observer_update;
669 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
671 GObjectClass *object_class;
673 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
674 object_class = (GObjectClass*) klass;
675 object_class->finalize = internal_folder_observer_finalize;
681 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
684 TnyList *folders = tny_simple_list_new ();
686 tny_folder_store_get_folders (store, folders, query, NULL);
687 iter = tny_list_create_iterator (folders);
689 while (!tny_iterator_is_done (iter)) {
691 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
693 tny_list_prepend (all_folders, G_OBJECT (folder));
694 recurse_folders (folder, query, all_folders);
695 g_object_unref (G_OBJECT (folder));
697 tny_iterator_next (iter);
699 g_object_unref (G_OBJECT (iter));
700 g_object_unref (G_OBJECT (folders));
704 * Issues the "progress-changed" signal. The timer won't be removed,
705 * so you must call g_source_remove to stop the signal emission
708 idle_notify_progress (gpointer data)
710 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
711 ModestMailOperationState *state;
713 state = modest_mail_operation_clone_state (mail_op);
714 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
715 g_slice_free (ModestMailOperationState, state);
721 * Issues the "progress-changed" signal and removes the timer. It uses
722 * a lock to ensure that the progress information of the mail
723 * operation is not modified while there are notifications pending
726 idle_notify_progress_once (gpointer data)
730 pair = (ModestPair *) data;
732 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
734 /* Free the state and the reference to the mail operation */
735 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
736 g_object_unref (pair->first);
742 * Used by update_account_thread to notify the queue from the main
743 * loop. We call it inside an idle call to achieve that
746 notify_update_account_queue (gpointer data)
748 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
750 modest_mail_operation_notify_end (mail_op);
751 g_object_unref (mail_op);
757 compare_headers_by_date (gconstpointer a,
760 TnyHeader **header1, **header2;
763 header1 = (TnyHeader **) a;
764 header2 = (TnyHeader **) b;
766 sent1 = tny_header_get_date_sent (*header1);
767 sent2 = tny_header_get_date_sent (*header2);
769 /* We want the most recent ones (greater time_t) at the
778 update_account_thread (gpointer thr_user_data)
780 UpdateAccountInfo *info;
781 TnyList *all_folders = NULL;
782 GPtrArray *new_headers;
783 TnyIterator *iter = NULL;
784 TnyFolderStoreQuery *query = NULL;
785 ModestMailOperationPrivate *priv;
787 info = (UpdateAccountInfo *) thr_user_data;
788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
790 /* Get account and set it into mail_operation */
791 priv->account = g_object_ref (info->account);
793 /* Get all the folders We can do it synchronously because
794 we're already running in a different thread than the UI */
795 all_folders = tny_simple_list_new ();
796 query = tny_folder_store_query_new ();
797 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
798 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
807 iter = tny_list_create_iterator (all_folders);
808 while (!tny_iterator_is_done (iter)) {
809 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
811 recurse_folders (folder, query, all_folders);
812 tny_iterator_next (iter);
814 g_object_unref (G_OBJECT (iter));
816 /* Update status and notify. We need to call the notification
817 with a source functopm in order to call it from the main
818 loop. We need that in order not to get into trouble with
819 Gtk+. We use a timeout in order to provide more status
820 information, because the sync tinymail call does not
821 provide it for the moment */
822 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
824 /* Refresh folders */
825 new_headers = g_ptr_array_new ();
826 iter = tny_list_create_iterator (all_folders);
827 while (!tny_iterator_is_done (iter) && !priv->error) {
829 InternalFolderObserver *observer;
830 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
832 /* Refresh the folder */
833 observer = g_object_new (internal_folder_observer_get_type (), NULL);
834 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
835 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
837 /* If the retrieve type is headers only do nothing more */
838 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
839 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
842 iter = tny_list_create_iterator (observer->new_headers);
843 while (!tny_iterator_is_done (iter)) {
844 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
845 /* Apply per-message size limits */
846 if (tny_header_get_message_size (header) < info->max_size)
847 g_ptr_array_add (new_headers, g_object_ref (header));
849 g_object_unref (header);
850 tny_iterator_next (iter);
852 g_object_unref (iter);
854 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
855 g_object_unref (observer);
858 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
860 g_object_unref (G_OBJECT (folder));
861 tny_iterator_next (iter);
863 g_object_unref (G_OBJECT (iter));
864 g_source_remove (timeout);
866 if (new_headers->len > 0) {
870 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
872 /* Apply message count limit */
873 /* TODO if the number of messages exceeds the maximum, ask the
874 user to download them all */
876 priv->total = MIN (new_headers->len, info->retrieve_limit);
877 while ((msg_num < priv->total)) {
879 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
880 TnyFolder *folder = tny_header_get_folder (header);
881 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
882 ModestMailOperationState *state;
886 /* We can not just use the mail operation because the
887 values of done and total could change before the
889 state = modest_mail_operation_clone_state (info->mail_op);
890 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
891 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
892 pair, (GDestroyNotify) modest_pair_free);
894 g_object_unref (msg);
895 g_object_unref (folder);
899 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
900 g_ptr_array_free (new_headers, FALSE);
904 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
907 if (priv->account != NULL)
908 g_object_unref (priv->account);
909 priv->account = g_object_ref (info->transport_account);
911 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
912 (info->transport_account);
914 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
915 modest_tny_send_queue_try_to_send (send_queue);
916 g_source_remove (timeout);
918 g_object_unref (G_OBJECT(send_queue));
920 /* Check if the operation was a success */
922 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
924 /* Update the last updated key */
925 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
926 tny_account_get_id (TNY_ACCOUNT (info->account)),
927 MODEST_ACCOUNT_LAST_UPDATED,
933 /* Notify about operation end. Note that the info could be
934 freed before this idle happens, but the mail operation will
936 g_idle_add (notify_update_account_queue, info->mail_op);
939 g_object_unref (query);
940 g_object_unref (all_folders);
941 g_object_unref (info->account);
942 g_object_unref (info->transport_account);
943 g_free (info->retrieve_type);
944 g_slice_free (UpdateAccountInfo, info);
950 modest_mail_operation_update_account (ModestMailOperation *self,
951 const gchar *account_name)
954 UpdateAccountInfo *info;
955 ModestMailOperationPrivate *priv;
956 ModestAccountMgr *mgr;
957 TnyStoreAccount *modest_account;
958 TnyTransportAccount *transport_account;
960 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
961 g_return_val_if_fail (account_name, FALSE);
963 /* Init mail operation. Set total and done to 0, and do not
964 update them, this way the progress objects will know that
965 we have no clue about the number of the objects */
966 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
969 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
971 /* Get the Modest account */
972 modest_account = (TnyStoreAccount *)
973 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
975 TNY_ACCOUNT_TYPE_STORE);
977 if (!modest_account) {
978 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
979 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
980 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
981 "cannot get tny store account for %s\n", account_name);
982 modest_mail_operation_notify_end (self);
986 /* Get the transport account, we can not do it in the thread
987 due to some problems with dbus */
988 transport_account = (TnyTransportAccount *)
989 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
991 if (!transport_account) {
992 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
993 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
994 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
995 "cannot get tny transport account for %s\n", account_name);
996 modest_mail_operation_notify_end (self);
1000 /* Create the helper object */
1001 info = g_slice_new (UpdateAccountInfo);
1002 info->mail_op = self;
1003 info->account = modest_account;
1004 info->transport_account = transport_account;
1006 /* Get the message size limit */
1007 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1008 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1009 if (info->max_size == 0)
1010 info->max_size = G_MAXINT;
1012 info->max_size = info->max_size * KB;
1014 /* Get per-account retrieval type */
1015 mgr = modest_runtime_get_account_mgr ();
1016 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1017 MODEST_ACCOUNT_RETRIEVE, FALSE);
1019 /* Get per-account message amount retrieval limit */
1020 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1021 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1022 if (info->retrieve_limit == 0)
1023 info->retrieve_limit = G_MAXINT;
1025 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1030 /* ******************************************************************* */
1031 /* ************************** STORE ACTIONS ************************* */
1032 /* ******************************************************************* */
1036 modest_mail_operation_create_folder (ModestMailOperation *self,
1037 TnyFolderStore *parent,
1040 ModestTnyFolderRules rules;
1041 ModestMailOperationPrivate *priv;
1042 TnyFolder *new_folder = NULL;
1043 gboolean can_create = FALSE;
1045 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1046 g_return_val_if_fail (name, NULL);
1048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1050 /* Get account and set it into mail_operation */
1051 priv->account = tny_folder_get_account (TNY_FOLDER(parent));
1054 if (!TNY_IS_FOLDER (parent)) {
1055 /* Set status failed and set an error */
1056 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1057 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1058 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1059 _("mail_in_ui_folder_create_error"));
1061 /* Check folder rules */
1062 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1063 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1064 /* Set status failed and set an error */
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1066 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1067 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1068 _("mail_in_ui_folder_create_error"));
1075 /* Create the folder */
1076 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1077 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1080 /* Notify about operation end */
1081 modest_mail_operation_notify_end (self);
1087 modest_mail_operation_remove_folder (ModestMailOperation *self,
1089 gboolean remove_to_trash)
1091 TnyAccount *account;
1092 ModestMailOperationPrivate *priv;
1093 ModestTnyFolderRules rules;
1095 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1096 g_return_if_fail (TNY_IS_FOLDER (folder));
1098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1100 /* Check folder rules */
1101 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1102 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1103 /* Set status failed and set an error */
1104 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1105 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1106 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1107 _("mail_in_ui_folder_delete_error"));
1111 /* Get the account */
1112 account = tny_folder_get_account (folder);
1113 priv->account = g_object_ref(account);
1115 /* Delete folder or move to trash */
1116 if (remove_to_trash) {
1117 TnyFolder *trash_folder = NULL;
1118 trash_folder = modest_tny_account_get_special_folder (account,
1119 TNY_FOLDER_TYPE_TRASH);
1120 /* TODO: error_handling */
1121 modest_mail_operation_xfer_folder (self, folder,
1122 TNY_FOLDER_STORE (trash_folder), TRUE);
1124 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1126 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1127 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1130 g_object_unref (G_OBJECT (parent));
1132 g_object_unref (G_OBJECT (account));
1135 /* Notify about operation end */
1136 modest_mail_operation_notify_end (self);
1140 transfer_folder_status_cb (GObject *obj,
1144 ModestMailOperation *self;
1145 ModestMailOperationPrivate *priv;
1146 ModestMailOperationState *state;
1148 g_return_if_fail (status != NULL);
1149 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1151 self = MODEST_MAIL_OPERATION (user_data);
1152 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1154 if ((status->position == 1) && (status->of_total == 100))
1157 priv->done = status->position;
1158 priv->total = status->of_total;
1160 state = modest_mail_operation_clone_state (self);
1161 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1162 g_slice_free (ModestMailOperationState, state);
1167 transfer_folder_cb (TnyFolder *folder,
1168 TnyFolderStore *into,
1170 TnyFolder *new_folder, GError **err,
1173 ModestMailOperation *self = NULL;
1174 ModestMailOperationPrivate *priv = NULL;
1176 self = MODEST_MAIL_OPERATION (user_data);
1178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1181 priv->error = g_error_copy (*err);
1183 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1184 } else if (cancelled) {
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1186 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1187 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1188 _("Transference of %s was cancelled."),
1189 tny_folder_get_name (folder));
1192 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1196 g_object_unref (folder);
1197 g_object_unref (into);
1198 if (new_folder != NULL)
1199 g_object_unref (new_folder);
1201 /* Notify about operation end */
1202 modest_mail_operation_notify_end (self);
1206 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1208 TnyFolderStore *parent,
1209 gboolean delete_original)
1211 ModestMailOperationPrivate *priv = NULL;
1212 ModestTnyFolderRules parent_rules, rules;
1214 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1215 g_return_if_fail (TNY_IS_FOLDER (folder));
1216 g_return_if_fail (TNY_IS_FOLDER (parent));
1218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1220 /* Get account and set it into mail_operation */
1221 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1222 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1224 /* Get folder rules */
1225 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1226 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1228 if (!TNY_IS_FOLDER_STORE (parent)) {
1232 /* The moveable restriction is applied also to copy operation */
1233 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1234 /* Set status failed and set an error */
1235 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1236 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1237 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1238 _("mail_in_ui_folder_move_target_error"));
1240 /* Notify the queue */
1241 modest_mail_operation_notify_end (self);
1242 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1243 /* Set status failed and set an error */
1244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1245 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1246 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1247 _("FIXME: parent folder does not accept new folders"));
1249 /* Notify the queue */
1250 modest_mail_operation_notify_end (self);
1252 /* Pick references for async calls */
1253 g_object_ref (folder);
1254 g_object_ref (parent);
1256 /* Move/Copy folder */
1257 tny_folder_copy_async (folder,
1259 tny_folder_get_name (folder),
1262 transfer_folder_status_cb,
1268 modest_mail_operation_rename_folder (ModestMailOperation *self,
1272 ModestMailOperationPrivate *priv;
1273 ModestTnyFolderRules rules;
1275 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1276 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1277 g_return_if_fail (name);
1279 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1281 /* Get account and set it into mail_operation */
1282 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1284 /* Check folder rules */
1285 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1286 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1287 /* Set status failed and set an error */
1288 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1289 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1290 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1291 _("FIXME: unable to rename"));
1293 /* Notify about operation end */
1294 modest_mail_operation_notify_end (self);
1296 /* Rename. Camel handles folder subscription/unsubscription */
1297 TnyFolderStore *into;
1299 into = tny_folder_get_folder_store (folder);
1300 tny_folder_copy_async (folder, into, name, TRUE,
1302 transfer_folder_status_cb,
1305 g_object_unref (into);
1310 /* ******************************************************************* */
1311 /* ************************** MSG ACTIONS ************************* */
1312 /* ******************************************************************* */
1314 void modest_mail_operation_get_msg (ModestMailOperation *self,
1316 GetMsgAsyncUserCallback user_callback,
1319 GetMsgAsyncHelper *helper = NULL;
1321 ModestMailOperationPrivate *priv;
1323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1324 g_return_if_fail (TNY_IS_HEADER (header));
1326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1327 folder = tny_header_get_folder (header);
1329 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1331 /* Get message from folder */
1333 /* Get account and set it into mail_operation */
1334 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1336 helper = g_slice_new0 (GetMsgAsyncHelper);
1337 helper->mail_op = self;
1338 helper->user_callback = user_callback;
1339 helper->pending_ops = 1;
1340 helper->user_data = user_data;
1342 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1344 g_object_unref (G_OBJECT (folder));
1346 /* Set status failed and set an error */
1347 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1348 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1349 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1350 _("Error trying to get a message. No folder found for header"));
1352 /* Notify the queue */
1353 modest_mail_operation_notify_end (self);
1358 get_msg_cb (TnyFolder *folder,
1364 GetMsgAsyncHelper *helper = NULL;
1365 ModestMailOperation *self = NULL;
1366 ModestMailOperationPrivate *priv = NULL;
1368 helper = (GetMsgAsyncHelper *) user_data;
1369 g_return_if_fail (helper != NULL);
1370 self = helper->mail_op;
1371 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1374 helper->pending_ops--;
1376 /* Check errors and cancel */
1378 priv->error = g_error_copy (*error);
1379 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1383 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1384 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1385 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1386 _("Error trying to refresh the contents of %s"),
1387 tny_folder_get_name (folder));
1391 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1393 /* If user defined callback function was defined, call it */
1394 if (helper->user_callback) {
1395 helper->user_callback (self, NULL, msg, helper->user_data);
1400 if (helper->pending_ops == 0) {
1401 g_slice_free (GetMsgAsyncHelper, helper);
1403 /* Notify about operation end */
1404 modest_mail_operation_notify_end (self);
1409 get_msg_status_cb (GObject *obj,
1413 GetMsgAsyncHelper *helper = NULL;
1414 ModestMailOperation *self;
1415 ModestMailOperationPrivate *priv;
1416 ModestMailOperationState *state;
1418 g_return_if_fail (status != NULL);
1419 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1421 helper = (GetMsgAsyncHelper *) user_data;
1422 g_return_if_fail (helper != NULL);
1424 self = helper->mail_op;
1425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1427 if ((status->position == 1) && (status->of_total == 100))
1433 state = modest_mail_operation_clone_state (self);
1434 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1435 g_slice_free (ModestMailOperationState, state);
1438 /****************************************************/
1440 ModestMailOperation *mail_op;
1442 GetMsgAsyncUserCallback user_callback;
1444 GDestroyNotify notify;
1448 GetMsgAsyncUserCallback user_callback;
1452 ModestMailOperation *mail_op;
1453 } NotifyGetMsgsInfo;
1457 * Used by get_msgs_full_thread to call the user_callback for each
1458 * message that has been read
1461 notify_get_msgs_full (gpointer data)
1463 NotifyGetMsgsInfo *info;
1465 info = (NotifyGetMsgsInfo *) data;
1467 /* Call the user callback */
1468 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1470 g_slice_free (NotifyGetMsgsInfo, info);
1476 * Used by get_msgs_full_thread to free al the thread resources and to
1477 * call the destroy function for the passed user_data
1480 get_msgs_full_destroyer (gpointer data)
1482 GetFullMsgsInfo *info;
1484 info = (GetFullMsgsInfo *) data;
1487 info->notify (info->user_data);
1490 g_object_unref (info->headers);
1491 g_slice_free (GetFullMsgsInfo, info);
1497 get_msgs_full_thread (gpointer thr_user_data)
1499 GetFullMsgsInfo *info;
1500 ModestMailOperationPrivate *priv = NULL;
1501 TnyIterator *iter = NULL;
1503 info = (GetFullMsgsInfo *) thr_user_data;
1504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1506 iter = tny_list_create_iterator (info->headers);
1507 while (!tny_iterator_is_done (iter)) {
1511 header = TNY_HEADER (tny_iterator_get_current (iter));
1512 folder = tny_header_get_folder (header);
1514 /* Get message from folder */
1517 /* The callback will call it per each header */
1518 msg = tny_folder_get_msg (folder, header, &(priv->error));
1521 ModestMailOperationState *state;
1526 /* notify progress */
1527 state = modest_mail_operation_clone_state (info->mail_op);
1528 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1529 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1530 pair, (GDestroyNotify) modest_pair_free);
1532 /* The callback is the responsible for
1533 freeing the message */
1534 if (info->user_callback) {
1535 NotifyGetMsgsInfo *info_notify;
1536 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1537 info_notify->user_callback = info->user_callback;
1538 info_notify->mail_op = info->mail_op;
1539 info_notify->header = g_object_ref (header);
1540 info_notify->msg = g_object_ref (msg);
1541 info_notify->user_data = info->user_data;
1542 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1543 notify_get_msgs_full,
1546 g_object_unref (msg);
1549 /* Set status failed and set an error */
1550 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1551 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1552 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1553 "Error trying to get a message. No folder found for header");
1555 g_object_unref (header);
1556 tny_iterator_next (iter);
1559 /* Notify about operation end */
1560 g_idle_add (notify_update_account_queue, info->mail_op);
1562 /* Free thread resources. Will be called after all previous idles */
1563 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1569 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1570 TnyList *header_list,
1571 GetMsgAsyncUserCallback user_callback,
1573 GDestroyNotify notify)
1575 TnyHeader *header = NULL;
1576 TnyFolder *folder = NULL;
1578 ModestMailOperationPrivate *priv = NULL;
1579 GetFullMsgsInfo *info = NULL;
1580 gboolean size_ok = TRUE;
1582 GError *error = NULL;
1583 TnyIterator *iter = NULL;
1585 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1587 /* Init mail operation */
1588 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1589 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1591 priv->total = tny_list_get_length(header_list);
1593 /* Get account and set it into mail_operation */
1594 if (tny_list_get_length (header_list) > 1) {
1595 iter = tny_list_create_iterator (header_list);
1596 header = TNY_HEADER (tny_iterator_get_current (iter));
1597 folder = tny_header_get_folder (header);
1598 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1599 g_object_unref (header);
1600 g_object_unref (folder);
1603 /* Get msg size limit */
1604 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1605 MODEST_CONF_MSG_SIZE_LIMIT,
1608 g_clear_error (&error);
1609 max_size = G_MAXINT;
1611 max_size = max_size * KB;
1614 /* Check message size limits. If there is only one message
1615 always retrieve it */
1617 while (!tny_iterator_is_done (iter) && size_ok) {
1618 header = TNY_HEADER (tny_iterator_get_current (iter));
1619 if (tny_header_get_message_size (header) >= max_size)
1621 g_object_unref (header);
1622 tny_iterator_next (iter);
1624 g_object_unref (iter);
1628 /* Create the info */
1629 info = g_slice_new0 (GetFullMsgsInfo);
1630 info->mail_op = self;
1631 info->user_callback = user_callback;
1632 info->user_data = user_data;
1633 info->headers = g_object_ref (header_list);
1634 info->notify = notify;
1636 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1638 /* Set status failed and set an error */
1639 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1640 /* FIXME: the error msg is different for pop */
1641 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1642 MODEST_MAIL_OPERATION_ERROR_SIZE_LIMIT,
1643 _("emev_ni_ui_imap_msg_size_exceed_error"));
1644 /* Remove from queue and free resources */
1645 modest_mail_operation_notify_end (self);
1653 modest_mail_operation_remove_msg (ModestMailOperation *self,
1655 gboolean remove_to_trash)
1658 ModestMailOperationPrivate *priv;
1660 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1661 g_return_if_fail (TNY_IS_HEADER (header));
1663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1664 folder = tny_header_get_folder (header);
1666 /* Get account and set it into mail_operation */
1667 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1669 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1671 /* Delete or move to trash */
1672 if (remove_to_trash) {
1673 TnyFolder *trash_folder;
1674 TnyStoreAccount *store_account;
1676 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1677 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1678 TNY_FOLDER_TYPE_TRASH);
1683 headers = tny_simple_list_new ();
1684 tny_list_append (headers, G_OBJECT (header));
1685 g_object_unref (header);
1688 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1689 g_object_unref (headers);
1690 /* g_object_unref (trash_folder); */
1692 ModestMailOperationPrivate *priv;
1694 /* Set status failed and set an error */
1695 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1699 _("Error trying to delete a message. Trash folder not found"));
1702 g_object_unref (G_OBJECT (store_account));
1704 tny_folder_remove_msg (folder, header, &(priv->error));
1706 tny_folder_sync(folder, TRUE, &(priv->error));
1711 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1713 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1716 g_object_unref (G_OBJECT (folder));
1718 /* Notify about operation end */
1719 modest_mail_operation_notify_end (self);
1723 transfer_msgs_status_cb (GObject *obj,
1727 XFerMsgAsyncHelper *helper = NULL;
1728 ModestMailOperation *self;
1729 ModestMailOperationPrivate *priv;
1730 ModestMailOperationState *state;
1733 g_return_if_fail (status != NULL);
1734 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1736 helper = (XFerMsgAsyncHelper *) user_data;
1737 g_return_if_fail (helper != NULL);
1739 self = helper->mail_op;
1740 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1742 if ((status->position == 1) && (status->of_total == 100))
1745 priv->done = status->position;
1746 priv->total = status->of_total;
1748 state = modest_mail_operation_clone_state (self);
1749 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1750 g_slice_free (ModestMailOperationState, state);
1755 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1757 XFerMsgAsyncHelper *helper;
1758 ModestMailOperation *self;
1759 ModestMailOperationPrivate *priv;
1761 helper = (XFerMsgAsyncHelper *) user_data;
1762 self = helper->mail_op;
1764 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1767 priv->error = g_error_copy (*err);
1769 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1770 } else if (cancelled) {
1771 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1772 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1773 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1774 _("Error trying to refresh the contents of %s"),
1775 tny_folder_get_name (folder));
1778 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1781 /* If user defined callback function was defined, call it */
1782 if (helper->user_callback) {
1783 helper->user_callback (priv->source, helper->user_data);
1787 g_object_unref (helper->headers);
1788 g_object_unref (helper->dest_folder);
1789 g_object_unref (helper->mail_op);
1790 g_slice_free (XFerMsgAsyncHelper, helper);
1791 g_object_unref (folder);
1793 /* Notify about operation end */
1794 modest_mail_operation_notify_end (self);
1798 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1801 gboolean delete_original,
1802 XferMsgsAsynUserCallback user_callback,
1805 ModestMailOperationPrivate *priv;
1807 TnyFolder *src_folder;
1808 XFerMsgAsyncHelper *helper;
1810 ModestTnyFolderRules rules;
1812 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1813 g_return_if_fail (TNY_IS_LIST (headers));
1814 g_return_if_fail (TNY_IS_FOLDER (folder));
1816 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1819 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1821 /* Apply folder rules */
1822 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1824 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1825 /* Set status failed and set an error */
1826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1827 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1828 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1829 _("FIXME: folder does not accept msgs"));
1830 /* Notify the queue */
1831 modest_mail_operation_notify_end (self);
1835 /* Create the helper */
1836 helper = g_slice_new0 (XFerMsgAsyncHelper);
1837 helper->mail_op = g_object_ref(self);
1838 helper->dest_folder = g_object_ref(folder);
1839 helper->headers = g_object_ref(headers);
1840 helper->user_callback = user_callback;
1841 helper->user_data = user_data;
1843 /* Get source folder */
1844 iter = tny_list_create_iterator (headers);
1845 header = TNY_HEADER (tny_iterator_get_current (iter));
1846 src_folder = tny_header_get_folder (header);
1847 g_object_unref (header);
1848 g_object_unref (iter);
1850 /* Get account and set it into mail_operation */
1851 priv->account = tny_folder_get_account (src_folder);
1853 /* Transfer messages */
1854 tny_folder_transfer_msgs_async (src_folder,
1859 transfer_msgs_status_cb,
1865 on_refresh_folder (TnyFolder *folder,
1870 ModestMailOperation *self;
1871 ModestMailOperationPrivate *priv;
1873 self = MODEST_MAIL_OPERATION (user_data);
1874 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1877 priv->error = g_error_copy (*error);
1878 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1884 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1885 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1886 _("Error trying to refresh the contents of %s"),
1887 tny_folder_get_name (folder));
1891 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1895 g_object_unref (folder);
1897 /* Notify about operation end */
1898 modest_mail_operation_notify_end (self);
1902 on_refresh_folder_status_update (GObject *obj,
1906 ModestMailOperation *self;
1907 ModestMailOperationPrivate *priv;
1908 ModestMailOperationState *state;
1910 g_return_if_fail (status != NULL);
1911 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1913 self = MODEST_MAIL_OPERATION (user_data);
1914 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1916 priv->done = status->position;
1917 priv->total = status->of_total;
1919 state = modest_mail_operation_clone_state (self);
1920 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1921 g_slice_free (ModestMailOperationState, state);
1925 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1928 ModestMailOperationPrivate *priv;
1930 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1932 /* Pick a reference */
1933 g_object_ref (folder);
1935 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1937 /* Get account and set it into mail_operation */
1938 priv->account = tny_folder_get_account (folder);
1940 /* Refresh the folder. TODO: tinymail could issue a status
1941 updates before the callback call then this could happen. We
1942 must review the design */
1943 tny_folder_refresh_async (folder,
1945 on_refresh_folder_status_update,
1951 * It's used by the mail operation queue to notify the observers
1952 * attached to that signal that the operation finished. We need to use
1953 * that because tinymail does not give us the progress of a given
1954 * operation when it finishes (it directly calls the operation
1958 modest_mail_operation_notify_end (ModestMailOperation *self)
1960 ModestMailOperationState *state;
1962 /* Notify the observers about the mail opertation end */
1963 state = modest_mail_operation_clone_state (self);
1964 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1965 g_slice_free (ModestMailOperationState, state);
1967 /* Notify the queue */
1968 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);