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.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-simple-list.h>
38 #include <tny-send-queue.h>
39 #include <tny-status.h>
40 #include <tny-folder-observer.h>
41 #include <camel/camel-stream-mem.h>
42 #include <glib/gi18n.h>
43 #include "modest-platform.h"
44 #include <modest-tny-account.h>
45 #include <modest-tny-send-queue.h>
46 #include <modest-runtime.h>
47 #include "modest-text-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-folder.h"
50 #include "modest-tny-platform-factory.h"
51 #include "modest-marshal.h"
52 #include "modest-error.h"
53 #include "modest-mail-operation.h"
57 /* 'private'/'protected' functions */
58 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
59 static void modest_mail_operation_init (ModestMailOperation *obj);
60 static void modest_mail_operation_finalize (GObject *obj);
62 static void get_msg_cb (TnyFolder *folder,
68 static void get_msg_status_cb (GObject *obj,
72 static void modest_mail_operation_notify_end (ModestMailOperation *self);
74 enum _ModestMailOperationSignals
76 PROGRESS_CHANGED_SIGNAL,
81 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
82 struct _ModestMailOperationPrivate {
88 ErrorCheckingUserCallback error_checking;
89 gpointer error_checking_user_data;
90 ModestMailOperationStatus status;
91 ModestMailOperationTypeOperation op_type;
94 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95 MODEST_TYPE_MAIL_OPERATION, \
96 ModestMailOperationPrivate))
98 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
99 priv->status = new_status;\
102 typedef struct _GetMsgAsyncHelper {
103 ModestMailOperation *mail_op;
104 GetMsgAsyncUserCallback user_callback;
109 typedef struct _XFerMsgAsyncHelper
111 ModestMailOperation *mail_op;
113 TnyFolder *dest_folder;
114 XferMsgsAsynUserCallback user_callback;
116 } XFerMsgAsyncHelper;
119 static GObjectClass *parent_class = NULL;
121 static guint signals[NUM_SIGNALS] = {0};
124 modest_mail_operation_get_type (void)
126 static GType my_type = 0;
128 static const GTypeInfo my_info = {
129 sizeof(ModestMailOperationClass),
130 NULL, /* base init */
131 NULL, /* base finalize */
132 (GClassInitFunc) modest_mail_operation_class_init,
133 NULL, /* class finalize */
134 NULL, /* class data */
135 sizeof(ModestMailOperation),
137 (GInstanceInitFunc) modest_mail_operation_init,
140 my_type = g_type_register_static (G_TYPE_OBJECT,
141 "ModestMailOperation",
148 modest_mail_operation_class_init (ModestMailOperationClass *klass)
150 GObjectClass *gobject_class;
151 gobject_class = (GObjectClass*) klass;
153 parent_class = g_type_class_peek_parent (klass);
154 gobject_class->finalize = modest_mail_operation_finalize;
156 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
159 * ModestMailOperation::progress-changed
160 * @self: the #MailOperation that emits the signal
161 * @user_data: user data set when the signal handler was connected
163 * Emitted when the progress of a mail operation changes
165 signals[PROGRESS_CHANGED_SIGNAL] =
166 g_signal_new ("progress-changed",
167 G_TYPE_FROM_CLASS (gobject_class),
169 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
171 g_cclosure_marshal_VOID__POINTER,
172 G_TYPE_NONE, 1, G_TYPE_POINTER);
176 modest_mail_operation_init (ModestMailOperation *obj)
178 ModestMailOperationPrivate *priv;
180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
182 priv->account = NULL;
183 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
184 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
189 priv->error_checking = NULL;
190 priv->error_checking_user_data = NULL;
194 modest_mail_operation_finalize (GObject *obj)
196 ModestMailOperationPrivate *priv;
198 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
201 g_error_free (priv->error);
205 g_object_unref (priv->source);
209 g_object_unref (priv->account);
210 priv->account = NULL;
214 G_OBJECT_CLASS(parent_class)->finalize (obj);
218 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
221 ModestMailOperation *obj;
222 ModestMailOperationPrivate *priv;
224 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
225 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
227 priv->op_type = op_type;
229 priv->source = g_object_ref(source);
235 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
237 ErrorCheckingUserCallback error_handler,
240 ModestMailOperation *obj;
241 ModestMailOperationPrivate *priv;
243 obj = modest_mail_operation_new (op_type, source);
244 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
246 g_return_val_if_fail (error_handler != NULL, obj);
247 priv->error_checking = error_handler;
253 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
255 ModestMailOperationPrivate *priv;
257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
258 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
260 if (priv->error_checking != NULL)
261 priv->error_checking (self, priv->error_checking_user_data);
265 ModestMailOperationTypeOperation
266 modest_mail_operation_get_type_operation (ModestMailOperation *self)
268 ModestMailOperationPrivate *priv;
270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
272 return priv->op_type;
276 modest_mail_operation_is_mine (ModestMailOperation *self,
279 ModestMailOperationPrivate *priv;
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 if (priv->source == NULL) return FALSE;
284 return priv->source == me;
288 modest_mail_operation_get_source (ModestMailOperation *self)
290 ModestMailOperationPrivate *priv;
292 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 return g_object_ref (priv->source);
297 ModestMailOperationStatus
298 modest_mail_operation_get_status (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
303 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
304 MODEST_MAIL_OPERATION_STATUS_INVALID);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
311 modest_mail_operation_get_error (ModestMailOperation *self)
313 ModestMailOperationPrivate *priv;
315 g_return_val_if_fail (self, NULL);
316 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
323 modest_mail_operation_cancel (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 if (!MODEST_IS_MAIL_OPERATION (self)) {
328 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
334 /* TODO: Tinymail does not support cancel operation */
335 /* tny_account_cancel (); */
338 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
340 /* Notify about operation end */
341 modest_mail_operation_notify_end (self);
347 modest_mail_operation_get_task_done (ModestMailOperation *self)
349 ModestMailOperationPrivate *priv;
351 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
358 modest_mail_operation_get_task_total (ModestMailOperation *self)
360 ModestMailOperationPrivate *priv;
362 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
369 modest_mail_operation_is_finished (ModestMailOperation *self)
371 ModestMailOperationPrivate *priv;
372 gboolean retval = FALSE;
374 if (!MODEST_IS_MAIL_OPERATION (self)) {
375 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
382 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
384 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
394 modest_mail_operation_get_id (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
405 modest_mail_operation_set_id (ModestMailOperation *self,
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 * Creates an image of the current state of a mail operation, the
418 * caller must free it
420 static ModestMailOperationState *
421 modest_mail_operation_clone_state (ModestMailOperation *self)
423 ModestMailOperationState *state;
424 ModestMailOperationPrivate *priv;
426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
428 state = g_slice_new (ModestMailOperationState);
430 state->status = priv->status;
431 state->op_type = priv->op_type;
432 state->done = priv->done;
433 state->total = priv->total;
434 state->finished = modest_mail_operation_is_finished (self);
439 /* ******************************************************************* */
440 /* ************************** SEND ACTIONS ************************* */
441 /* ******************************************************************* */
444 modest_mail_operation_send_mail (ModestMailOperation *self,
445 TnyTransportAccount *transport_account,
448 TnySendQueue *send_queue = NULL;
449 ModestMailOperationPrivate *priv;
451 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
452 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
453 g_return_if_fail (TNY_IS_MSG (msg));
455 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
457 /* Get account and set it into mail_operation */
458 priv->account = g_object_ref (transport_account);
460 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
461 if (!TNY_IS_SEND_QUEUE(send_queue)) {
462 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
463 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
464 "modest: could not find send queue for account\n");
466 tny_send_queue_add (send_queue, msg, &(priv->error));
469 /* Notify about operation end */
470 modest_mail_operation_notify_end (self);
474 modest_mail_operation_send_new_mail (ModestMailOperation *self,
475 TnyTransportAccount *transport_account,
476 const gchar *from, const gchar *to,
477 const gchar *cc, const gchar *bcc,
478 const gchar *subject, const gchar *plain_body,
479 const gchar *html_body,
480 const GList *attachments_list,
481 TnyHeaderFlags priority_flags)
483 TnyMsg *new_msg = NULL;
484 ModestMailOperationPrivate *priv = NULL;
486 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
487 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
491 /* Get account and set it into mail_operation */
492 priv->account = g_object_ref (transport_account);
494 /* Check parametters */
496 /* Set status failed and set an error */
497 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
498 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
499 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
500 _("Error trying to send a mail. You need to set at least one recipient"));
504 if (html_body == NULL) {
505 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
507 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
510 g_printerr ("modest: failed to create a new msg\n");
514 /* TODO: add priority handling. It's received in the priority_flags operator, and
515 it should have effect in the sending operation */
517 /* Call mail operation */
518 modest_mail_operation_send_mail (self, transport_account, new_msg);
521 g_object_unref (G_OBJECT (new_msg));
525 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
526 TnyTransportAccount *transport_account,
527 const gchar *from, const gchar *to,
528 const gchar *cc, const gchar *bcc,
529 const gchar *subject, const gchar *plain_body,
530 const gchar *html_body,
531 const GList *attachments_list,
532 TnyHeaderFlags priority_flags)
535 TnyFolder *folder = NULL;
536 ModestMailOperationPrivate *priv = NULL;
538 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
539 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
541 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
543 /* Get account and set it into mail_operation */
544 priv->account = g_object_ref (transport_account);
546 if (html_body == NULL) {
547 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
549 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
552 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
553 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
554 "modest: failed to create a new msg\n");
558 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
561 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
562 "modest: failed to create a new msg\n");
566 tny_folder_add_msg (folder, msg, &(priv->error));
572 g_object_unref (G_OBJECT(msg));
574 g_object_unref (G_OBJECT(folder));
576 modest_mail_operation_notify_end (self);
581 ModestMailOperation *mail_op;
582 TnyStoreAccount *account;
583 TnyTransportAccount *transport_account;
586 gchar *retrieve_type;
589 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
590 /* We use this folder observer to track the headers that have been
591 * added to a folder */
594 TnyList *new_headers;
595 } InternalFolderObserver;
599 } InternalFolderObserverClass;
601 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
603 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
604 internal_folder_observer,
606 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
610 foreach_add_item (gpointer header, gpointer user_data)
612 tny_list_prepend (TNY_LIST (user_data),
613 g_object_ref (G_OBJECT (header)));
616 /* This is the method that looks for new messages in a folder */
618 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
620 TnyFolderChangeChanged changed;
622 changed = tny_folder_change_get_changed (change);
624 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
627 /* Get added headers */
628 list = tny_simple_list_new ();
629 tny_folder_change_get_added_headers (change, list);
631 /* Add them to the folder observer */
632 tny_list_foreach (list, foreach_add_item,
633 ((InternalFolderObserver *)self)->new_headers);
635 g_object_unref (G_OBJECT (list));
640 internal_folder_observer_init (InternalFolderObserver *self)
642 self->new_headers = tny_simple_list_new ();
645 internal_folder_observer_finalize (GObject *object)
647 InternalFolderObserver *self;
649 self = (InternalFolderObserver *) object;
650 g_object_unref (self->new_headers);
652 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
655 tny_folder_observer_init (TnyFolderObserverIface *iface)
657 iface->update_func = internal_folder_observer_update;
660 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
662 GObjectClass *object_class;
664 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
665 object_class = (GObjectClass*) klass;
666 object_class->finalize = internal_folder_observer_finalize;
672 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
675 TnyList *folders = tny_simple_list_new ();
677 tny_folder_store_get_folders (store, folders, query, NULL);
678 iter = tny_list_create_iterator (folders);
680 while (!tny_iterator_is_done (iter)) {
682 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
684 tny_list_prepend (all_folders, G_OBJECT (folder));
685 recurse_folders (folder, query, all_folders);
686 g_object_unref (G_OBJECT (folder));
688 tny_iterator_next (iter);
690 g_object_unref (G_OBJECT (iter));
691 g_object_unref (G_OBJECT (folders));
695 * Issues the "progress-changed" signal. The timer won't be removed,
696 * so you must call g_source_remove to stop the signal emission
699 idle_notify_progress (gpointer data)
701 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
702 ModestMailOperationState *state;
704 state = modest_mail_operation_clone_state (mail_op);
705 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
706 g_slice_free (ModestMailOperationState, state);
712 * Issues the "progress-changed" signal and removes the timer. It uses
713 * a lock to ensure that the progress information of the mail
714 * operation is not modified while there are notifications pending
717 idle_notify_progress_once (gpointer data)
721 pair = (ModestPair *) data;
723 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
725 /* Free the state and the reference to the mail operation */
726 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
727 g_object_unref (pair->first);
733 * Used by update_account_thread to notify the queue from the main
734 * loop. We call it inside an idle call to achieve that
737 notify_update_account_queue (gpointer data)
739 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
741 modest_mail_operation_notify_end (mail_op);
742 g_object_unref (mail_op);
748 compare_headers_by_date (gconstpointer a,
751 TnyHeader **header1, **header2;
754 header1 = (TnyHeader **) a;
755 header2 = (TnyHeader **) b;
757 sent1 = tny_header_get_date_sent (*header1);
758 sent2 = tny_header_get_date_sent (*header2);
760 /* We want the most recent ones (greater time_t) at the
769 update_account_thread (gpointer thr_user_data)
771 UpdateAccountInfo *info;
772 TnyList *all_folders = NULL;
773 GPtrArray *new_headers;
774 TnyIterator *iter = NULL;
775 TnyFolderStoreQuery *query = NULL;
776 ModestMailOperationPrivate *priv;
778 info = (UpdateAccountInfo *) thr_user_data;
779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
781 /* Get account and set it into mail_operation */
782 priv->account = g_object_ref (info->account);
784 /* Get all the folders We can do it synchronously because
785 we're already running in a different thread than the UI */
786 all_folders = tny_simple_list_new ();
787 query = tny_folder_store_query_new ();
788 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
789 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
794 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
798 iter = tny_list_create_iterator (all_folders);
799 while (!tny_iterator_is_done (iter)) {
800 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
802 recurse_folders (folder, query, all_folders);
803 tny_iterator_next (iter);
805 g_object_unref (G_OBJECT (iter));
807 /* Update status and notify. We need to call the notification
808 with a source functopm in order to call it from the main
809 loop. We need that in order not to get into trouble with
810 Gtk+. We use a timeout in order to provide more status
811 information, because the sync tinymail call does not
812 provide it for the moment */
813 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
815 /* Refresh folders */
816 new_headers = g_ptr_array_new ();
817 iter = tny_list_create_iterator (all_folders);
818 while (!tny_iterator_is_done (iter) && !priv->error) {
820 InternalFolderObserver *observer;
821 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
823 /* Refresh the folder */
824 observer = g_object_new (internal_folder_observer_get_type (), NULL);
825 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
826 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
828 /* If the retrieve type is headers only do nothing more */
829 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
830 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
833 iter = tny_list_create_iterator (observer->new_headers);
834 while (!tny_iterator_is_done (iter)) {
835 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
836 /* Apply per-message size limits */
837 if (tny_header_get_message_size (header) < info->max_size)
838 g_ptr_array_add (new_headers, g_object_ref (header));
840 g_object_unref (header);
841 tny_iterator_next (iter);
843 g_object_unref (iter);
845 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
846 g_object_unref (observer);
849 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
851 g_object_unref (G_OBJECT (folder));
852 tny_iterator_next (iter);
854 g_object_unref (G_OBJECT (iter));
855 g_source_remove (timeout);
857 if (new_headers->len > 0) {
861 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
863 /* Apply message count limit */
864 /* TODO if the number of messages exceeds the maximum, ask the
865 user to download them all */
867 priv->total = MIN (new_headers->len, info->retrieve_limit);
868 while ((msg_num < priv->total)) {
870 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
871 TnyFolder *folder = tny_header_get_folder (header);
872 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
873 ModestMailOperationState *state;
877 /* We can not just use the mail operation because the
878 values of done and total could change before the
880 state = modest_mail_operation_clone_state (info->mail_op);
881 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
882 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
883 pair, (GDestroyNotify) modest_pair_free);
885 g_object_unref (msg);
886 g_object_unref (folder);
890 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
891 g_ptr_array_free (new_headers, FALSE);
895 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
898 if (priv->account != NULL)
899 g_object_unref (priv->account);
900 priv->account = g_object_ref (info->transport_account);
902 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
903 (info->transport_account);
905 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
906 modest_tny_send_queue_try_to_send (send_queue);
907 g_source_remove (timeout);
909 g_object_unref (G_OBJECT(send_queue));
911 /* Check if the operation was a success */
913 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
915 /* Update the last updated key */
916 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
917 tny_account_get_id (TNY_ACCOUNT (info->account)),
918 MODEST_ACCOUNT_LAST_UPDATED,
924 /* Notify about operation end. Note that the info could be
925 freed before this idle happens, but the mail operation will
927 g_idle_add (notify_update_account_queue, info->mail_op);
930 g_object_unref (query);
931 g_object_unref (all_folders);
932 g_object_unref (info->account);
933 g_object_unref (info->transport_account);
934 g_free (info->retrieve_type);
935 g_slice_free (UpdateAccountInfo, info);
941 modest_mail_operation_update_account (ModestMailOperation *self,
942 const gchar *account_name)
945 UpdateAccountInfo *info;
946 ModestMailOperationPrivate *priv;
947 ModestAccountMgr *mgr;
948 TnyStoreAccount *modest_account;
949 TnyTransportAccount *transport_account;
951 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
952 g_return_val_if_fail (account_name, FALSE);
954 /* Init mail operation. Set total and done to 0, and do not
955 update them, this way the progress objects will know that
956 we have no clue about the number of the objects */
957 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
960 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
962 /* Get the Modest account */
963 modest_account = (TnyStoreAccount *)
964 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
966 TNY_ACCOUNT_TYPE_STORE);
968 if (!modest_account) {
969 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
970 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
971 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
972 "cannot get tny store account for %s\n", account_name);
973 modest_mail_operation_notify_end (self);
977 /* Get the transport account, we can not do it in the thread
978 due to some problems with dbus */
979 transport_account = (TnyTransportAccount *)
980 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
982 if (!transport_account) {
983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
984 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
985 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
986 "cannot get tny transport account for %s\n", account_name);
987 modest_mail_operation_notify_end (self);
991 /* Create the helper object */
992 info = g_slice_new (UpdateAccountInfo);
993 info->mail_op = self;
994 info->account = modest_account;
995 info->transport_account = transport_account;
997 /* Get the message size limit */
998 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
999 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1000 if (info->max_size == 0)
1001 info->max_size = G_MAXINT;
1003 info->max_size = info->max_size * KB;
1005 /* Get per-account retrieval type */
1006 mgr = modest_runtime_get_account_mgr ();
1007 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1008 MODEST_ACCOUNT_RETRIEVE, FALSE);
1010 /* Get per-account message amount retrieval limit */
1011 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1012 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1013 if (info->retrieve_limit == 0)
1014 info->retrieve_limit = G_MAXINT;
1016 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1021 /* ******************************************************************* */
1022 /* ************************** STORE ACTIONS ************************* */
1023 /* ******************************************************************* */
1027 modest_mail_operation_create_folder (ModestMailOperation *self,
1028 TnyFolderStore *parent,
1031 ModestTnyFolderRules rules;
1032 ModestMailOperationPrivate *priv;
1033 TnyFolder *new_folder = NULL;
1034 gboolean can_create = FALSE;
1036 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1037 g_return_val_if_fail (name, NULL);
1039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1041 /* Get account and set it into mail_operation */
1042 priv->account = tny_folder_get_account (TNY_FOLDER(parent));
1045 if (!TNY_IS_FOLDER (parent)) {
1046 /* Set status failed and set an error */
1047 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1048 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1049 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1050 _("mail_in_ui_folder_create_error"));
1052 /* Check folder rules */
1053 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1054 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
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_FOLDER_RULES,
1059 _("mail_in_ui_folder_create_error"));
1066 /* Create the folder */
1067 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1068 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1071 /* Notify about operation end */
1072 modest_mail_operation_notify_end (self);
1078 modest_mail_operation_remove_folder (ModestMailOperation *self,
1080 gboolean remove_to_trash)
1082 TnyAccount *account;
1083 ModestMailOperationPrivate *priv;
1084 ModestTnyFolderRules rules;
1086 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1087 g_return_if_fail (TNY_IS_FOLDER (folder));
1089 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1091 /* Check folder rules */
1092 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1093 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1094 /* Set status failed and set an error */
1095 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1096 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1097 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1098 _("mail_in_ui_folder_delete_error"));
1102 /* Get the account */
1103 account = tny_folder_get_account (folder);
1104 priv->account = g_object_ref(account);
1106 /* Delete folder or move to trash */
1107 if (remove_to_trash) {
1108 TnyFolder *trash_folder = NULL;
1109 trash_folder = modest_tny_account_get_special_folder (account,
1110 TNY_FOLDER_TYPE_TRASH);
1111 /* TODO: error_handling */
1112 modest_mail_operation_xfer_folder (self, folder,
1113 TNY_FOLDER_STORE (trash_folder), TRUE);
1115 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1117 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1118 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1121 g_object_unref (G_OBJECT (parent));
1123 g_object_unref (G_OBJECT (account));
1126 /* Notify about operation end */
1127 modest_mail_operation_notify_end (self);
1131 transfer_folder_status_cb (GObject *obj,
1135 ModestMailOperation *self;
1136 ModestMailOperationPrivate *priv;
1137 ModestMailOperationState *state;
1139 g_return_if_fail (status != NULL);
1140 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1142 self = MODEST_MAIL_OPERATION (user_data);
1143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1145 if ((status->position == 1) && (status->of_total == 100))
1148 priv->done = status->position;
1149 priv->total = status->of_total;
1151 state = modest_mail_operation_clone_state (self);
1152 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1153 g_slice_free (ModestMailOperationState, state);
1158 transfer_folder_cb (TnyFolder *folder,
1159 TnyFolderStore *into,
1161 TnyFolder *new_folder, GError **err,
1164 ModestMailOperation *self = NULL;
1165 ModestMailOperationPrivate *priv = NULL;
1167 self = MODEST_MAIL_OPERATION (user_data);
1169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1172 priv->error = g_error_copy (*err);
1174 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1175 } else if (cancelled) {
1176 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1177 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1178 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1179 _("Transference of %s was cancelled."),
1180 tny_folder_get_name (folder));
1183 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1187 g_object_unref (folder);
1188 g_object_unref (into);
1189 if (new_folder != NULL)
1190 g_object_unref (new_folder);
1192 /* Notify about operation end */
1193 modest_mail_operation_notify_end (self);
1197 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1199 TnyFolderStore *parent,
1200 gboolean delete_original)
1202 ModestMailOperationPrivate *priv = NULL;
1203 ModestTnyFolderRules parent_rules, rules;
1205 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1206 g_return_if_fail (TNY_IS_FOLDER (folder));
1207 g_return_if_fail (TNY_IS_FOLDER (parent));
1209 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1211 /* Get account and set it into mail_operation */
1212 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1213 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1215 /* Get folder rules */
1216 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1217 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1219 if (!TNY_IS_FOLDER_STORE (parent)) {
1223 /* The moveable restriction is applied also to copy operation */
1224 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1225 /* Set status failed and set an error */
1226 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1227 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1228 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1229 _("mail_in_ui_folder_move_target_error"));
1231 /* Notify the queue */
1232 modest_mail_operation_notify_end (self);
1233 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
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 _("FIXME: parent folder does not accept new folders"));
1240 /* Notify the queue */
1241 modest_mail_operation_notify_end (self);
1243 /* Pick references for async calls */
1244 g_object_ref (folder);
1245 g_object_ref (parent);
1247 /* Move/Copy folder */
1248 tny_folder_copy_async (folder,
1250 tny_folder_get_name (folder),
1253 transfer_folder_status_cb,
1259 modest_mail_operation_rename_folder (ModestMailOperation *self,
1263 ModestMailOperationPrivate *priv;
1264 ModestTnyFolderRules rules;
1266 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1267 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1268 g_return_if_fail (name);
1270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1272 /* Get account and set it into mail_operation */
1273 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1275 /* Check folder rules */
1276 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1277 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1278 /* Set status failed and set an error */
1279 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1280 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1281 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1282 _("FIXME: unable to rename"));
1284 /* Notify about operation end */
1285 modest_mail_operation_notify_end (self);
1287 /* Rename. Camel handles folder subscription/unsubscription */
1288 TnyFolderStore *into;
1290 into = tny_folder_get_folder_store (folder);
1291 tny_folder_copy_async (folder, into, name, TRUE,
1293 transfer_folder_status_cb,
1296 g_object_unref (into);
1301 /* ******************************************************************* */
1302 /* ************************** MSG ACTIONS ************************* */
1303 /* ******************************************************************* */
1305 void modest_mail_operation_get_msg (ModestMailOperation *self,
1307 GetMsgAsyncUserCallback user_callback,
1310 GetMsgAsyncHelper *helper = NULL;
1312 ModestMailOperationPrivate *priv;
1314 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1315 g_return_if_fail (TNY_IS_HEADER (header));
1317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1318 folder = tny_header_get_folder (header);
1320 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1322 /* Get message from folder */
1324 /* Get account and set it into mail_operation */
1325 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1327 helper = g_slice_new0 (GetMsgAsyncHelper);
1328 helper->mail_op = self;
1329 helper->user_callback = user_callback;
1330 helper->pending_ops = 1;
1331 helper->user_data = user_data;
1333 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1335 g_object_unref (G_OBJECT (folder));
1337 /* Set status failed and set an error */
1338 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1339 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1340 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1341 _("Error trying to get a message. No folder found for header"));
1343 /* Notify the queue */
1344 modest_mail_operation_notify_end (self);
1349 get_msg_cb (TnyFolder *folder,
1355 GetMsgAsyncHelper *helper = NULL;
1356 ModestMailOperation *self = NULL;
1357 ModestMailOperationPrivate *priv = NULL;
1359 helper = (GetMsgAsyncHelper *) user_data;
1360 g_return_if_fail (helper != NULL);
1361 self = helper->mail_op;
1362 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1365 helper->pending_ops--;
1367 /* Check errors and cancel */
1369 priv->error = g_error_copy (*error);
1370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1374 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1375 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1376 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1377 _("Error trying to refresh the contents of %s"),
1378 tny_folder_get_name (folder));
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1384 /* If user defined callback function was defined, call it */
1385 if (helper->user_callback) {
1386 helper->user_callback (self, NULL, msg, helper->user_data);
1391 if (helper->pending_ops == 0) {
1392 g_slice_free (GetMsgAsyncHelper, helper);
1394 /* Notify about operation end */
1395 modest_mail_operation_notify_end (self);
1400 get_msg_status_cb (GObject *obj,
1404 GetMsgAsyncHelper *helper = NULL;
1405 ModestMailOperation *self;
1406 ModestMailOperationPrivate *priv;
1407 ModestMailOperationState *state;
1409 g_return_if_fail (status != NULL);
1410 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1412 helper = (GetMsgAsyncHelper *) user_data;
1413 g_return_if_fail (helper != NULL);
1415 self = helper->mail_op;
1416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1418 if ((status->position == 1) && (status->of_total == 100))
1424 state = modest_mail_operation_clone_state (self);
1425 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1426 g_slice_free (ModestMailOperationState, state);
1429 /****************************************************/
1431 ModestMailOperation *mail_op;
1433 GetMsgAsyncUserCallback user_callback;
1435 GDestroyNotify notify;
1439 GetMsgAsyncUserCallback user_callback;
1443 ModestMailOperation *mail_op;
1444 } NotifyGetMsgsInfo;
1448 * Used by get_msgs_full_thread to call the user_callback for each
1449 * message that has been read
1452 notify_get_msgs_full (gpointer data)
1454 NotifyGetMsgsInfo *info;
1456 info = (NotifyGetMsgsInfo *) data;
1458 /* Call the user callback */
1459 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1461 g_slice_free (NotifyGetMsgsInfo, info);
1467 * Used by get_msgs_full_thread to free al the thread resources and to
1468 * call the destroy function for the passed user_data
1471 get_msgs_full_destroyer (gpointer data)
1473 GetFullMsgsInfo *info;
1475 info = (GetFullMsgsInfo *) data;
1478 info->notify (info->user_data);
1481 g_object_unref (info->headers);
1482 g_slice_free (GetFullMsgsInfo, info);
1488 get_msgs_full_thread (gpointer thr_user_data)
1490 GetFullMsgsInfo *info;
1491 ModestMailOperationPrivate *priv = NULL;
1492 TnyIterator *iter = NULL;
1494 info = (GetFullMsgsInfo *) thr_user_data;
1495 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1497 iter = tny_list_create_iterator (info->headers);
1498 while (!tny_iterator_is_done (iter)) {
1502 header = TNY_HEADER (tny_iterator_get_current (iter));
1503 folder = tny_header_get_folder (header);
1505 /* Get message from folder */
1508 /* The callback will call it per each header */
1509 msg = tny_folder_get_msg (folder, header, &(priv->error));
1512 ModestMailOperationState *state;
1517 /* notify progress */
1518 state = modest_mail_operation_clone_state (info->mail_op);
1519 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1520 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1521 pair, (GDestroyNotify) modest_pair_free);
1523 /* The callback is the responsible for
1524 freeing the message */
1525 if (info->user_callback) {
1526 NotifyGetMsgsInfo *info_notify;
1527 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1528 info_notify->user_callback = info->user_callback;
1529 info_notify->mail_op = info->mail_op;
1530 info_notify->header = g_object_ref (header);
1531 info_notify->msg = g_object_ref (msg);
1532 info_notify->user_data = info->user_data;
1533 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1534 notify_get_msgs_full,
1537 g_object_unref (msg);
1540 /* Set status failed and set an error */
1541 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1542 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1543 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1544 "Error trying to get a message. No folder found for header");
1546 g_object_unref (header);
1547 tny_iterator_next (iter);
1550 /* Set operation status */
1551 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1552 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1554 /* Notify about operation end */
1555 g_idle_add (notify_update_account_queue, info->mail_op);
1557 /* Free thread resources. Will be called after all previous idles */
1558 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1564 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1565 TnyList *header_list,
1566 GetMsgAsyncUserCallback user_callback,
1568 GDestroyNotify notify)
1570 TnyHeader *header = NULL;
1571 TnyFolder *folder = NULL;
1573 ModestMailOperationPrivate *priv = NULL;
1574 GetFullMsgsInfo *info = NULL;
1575 gboolean size_ok = TRUE;
1577 TnyIterator *iter = NULL;
1579 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1581 /* Init mail operation */
1582 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1583 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1585 priv->total = tny_list_get_length(header_list);
1587 /* Get account and set it into mail_operation */
1588 if (tny_list_get_length (header_list) > 1) {
1589 iter = tny_list_create_iterator (header_list);
1590 header = TNY_HEADER (tny_iterator_get_current (iter));
1591 folder = tny_header_get_folder (header);
1592 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1593 g_object_unref (header);
1594 g_object_unref (folder);
1597 /* Get msg size limit */
1598 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1599 MODEST_CONF_MSG_SIZE_LIMIT,
1602 g_clear_error (&(priv->error));
1603 max_size = G_MAXINT;
1605 max_size = max_size * KB;
1608 /* Check message size limits. If there is only one message
1609 always retrieve it */
1611 while (!tny_iterator_is_done (iter) && size_ok) {
1612 header = TNY_HEADER (tny_iterator_get_current (iter));
1613 if (tny_header_get_message_size (header) >= max_size)
1615 g_object_unref (header);
1616 tny_iterator_next (iter);
1618 g_object_unref (iter);
1622 /* Create the info */
1623 info = g_slice_new0 (GetFullMsgsInfo);
1624 info->mail_op = self;
1625 info->user_callback = user_callback;
1626 info->user_data = user_data;
1627 info->headers = g_object_ref (header_list);
1628 info->notify = notify;
1630 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1632 /* Set status failed and set an error */
1633 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1634 /* FIXME: the error msg is different for pop */
1635 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1636 MODEST_MAIL_OPERATION_ERROR_SIZE_LIMIT,
1637 _("emev_ni_ui_imap_msg_size_exceed_error"));
1638 /* Remove from queue and free resources */
1639 modest_mail_operation_notify_end (self);
1647 modest_mail_operation_remove_msg (ModestMailOperation *self,
1649 gboolean remove_to_trash)
1652 ModestMailOperationPrivate *priv;
1654 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1655 g_return_if_fail (TNY_IS_HEADER (header));
1657 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1658 folder = tny_header_get_folder (header);
1660 /* Get account and set it into mail_operation */
1661 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1665 /* Delete or move to trash */
1666 if (remove_to_trash) {
1667 TnyFolder *trash_folder;
1668 TnyStoreAccount *store_account;
1670 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1671 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1672 TNY_FOLDER_TYPE_TRASH);
1677 headers = tny_simple_list_new ();
1678 tny_list_append (headers, G_OBJECT (header));
1679 g_object_unref (header);
1682 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1683 g_object_unref (headers);
1684 /* g_object_unref (trash_folder); */
1686 ModestMailOperationPrivate *priv;
1688 /* Set status failed and set an error */
1689 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1690 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1692 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1693 _("Error trying to delete a message. Trash folder not found"));
1696 g_object_unref (G_OBJECT (store_account));
1698 tny_folder_remove_msg (folder, header, &(priv->error));
1700 tny_folder_sync(folder, TRUE, &(priv->error));
1705 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1710 g_object_unref (G_OBJECT (folder));
1712 /* Notify about operation end */
1713 modest_mail_operation_notify_end (self);
1717 transfer_msgs_status_cb (GObject *obj,
1721 XFerMsgAsyncHelper *helper = NULL;
1722 ModestMailOperation *self;
1723 ModestMailOperationPrivate *priv;
1724 ModestMailOperationState *state;
1727 g_return_if_fail (status != NULL);
1728 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1730 helper = (XFerMsgAsyncHelper *) user_data;
1731 g_return_if_fail (helper != NULL);
1733 self = helper->mail_op;
1734 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1736 if ((status->position == 1) && (status->of_total == 100))
1739 priv->done = status->position;
1740 priv->total = status->of_total;
1742 state = modest_mail_operation_clone_state (self);
1743 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1744 g_slice_free (ModestMailOperationState, state);
1749 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1751 XFerMsgAsyncHelper *helper;
1752 ModestMailOperation *self;
1753 ModestMailOperationPrivate *priv;
1755 helper = (XFerMsgAsyncHelper *) user_data;
1756 self = helper->mail_op;
1758 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1761 priv->error = g_error_copy (*err);
1763 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1764 } else if (cancelled) {
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1766 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1767 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1768 _("Error trying to refresh the contents of %s"),
1769 tny_folder_get_name (folder));
1772 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1775 /* If user defined callback function was defined, call it */
1776 if (helper->user_callback) {
1777 helper->user_callback (priv->source, helper->user_data);
1781 g_object_unref (helper->headers);
1782 g_object_unref (helper->dest_folder);
1783 g_object_unref (helper->mail_op);
1784 g_slice_free (XFerMsgAsyncHelper, helper);
1785 g_object_unref (folder);
1787 /* Notify about operation end */
1788 modest_mail_operation_notify_end (self);
1792 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1795 gboolean delete_original,
1796 XferMsgsAsynUserCallback user_callback,
1799 ModestMailOperationPrivate *priv;
1801 TnyFolder *src_folder;
1802 XFerMsgAsyncHelper *helper;
1804 ModestTnyFolderRules rules;
1806 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1807 g_return_if_fail (TNY_IS_LIST (headers));
1808 g_return_if_fail (TNY_IS_FOLDER (folder));
1810 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1813 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1815 /* Apply folder rules */
1816 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1818 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1819 /* Set status failed and set an error */
1820 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1821 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1822 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1823 _("FIXME: folder does not accept msgs"));
1824 /* Notify the queue */
1825 modest_mail_operation_notify_end (self);
1829 /* Create the helper */
1830 helper = g_slice_new0 (XFerMsgAsyncHelper);
1831 helper->mail_op = g_object_ref(self);
1832 helper->dest_folder = g_object_ref(folder);
1833 helper->headers = g_object_ref(headers);
1834 helper->user_callback = user_callback;
1835 helper->user_data = user_data;
1837 /* Get source folder */
1838 iter = tny_list_create_iterator (headers);
1839 header = TNY_HEADER (tny_iterator_get_current (iter));
1840 src_folder = tny_header_get_folder (header);
1841 g_object_unref (header);
1842 g_object_unref (iter);
1844 /* Get account and set it into mail_operation */
1845 priv->account = tny_folder_get_account (src_folder);
1847 /* Transfer messages */
1848 tny_folder_transfer_msgs_async (src_folder,
1853 transfer_msgs_status_cb,
1859 on_refresh_folder (TnyFolder *folder,
1864 ModestMailOperation *self;
1865 ModestMailOperationPrivate *priv;
1867 self = MODEST_MAIL_OPERATION (user_data);
1868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1871 priv->error = g_error_copy (*error);
1872 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1877 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1878 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1879 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1880 _("Error trying to refresh the contents of %s"),
1881 tny_folder_get_name (folder));
1885 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1889 g_object_unref (folder);
1891 /* Notify about operation end */
1892 modest_mail_operation_notify_end (self);
1896 on_refresh_folder_status_update (GObject *obj,
1900 ModestMailOperation *self;
1901 ModestMailOperationPrivate *priv;
1902 ModestMailOperationState *state;
1904 g_return_if_fail (status != NULL);
1905 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1907 self = MODEST_MAIL_OPERATION (user_data);
1908 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1910 priv->done = status->position;
1911 priv->total = status->of_total;
1913 state = modest_mail_operation_clone_state (self);
1914 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1915 g_slice_free (ModestMailOperationState, state);
1919 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1922 ModestMailOperationPrivate *priv;
1924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1926 /* Pick a reference */
1927 g_object_ref (folder);
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1931 /* Get account and set it into mail_operation */
1932 priv->account = tny_folder_get_account (folder);
1934 /* Refresh the folder. TODO: tinymail could issue a status
1935 updates before the callback call then this could happen. We
1936 must review the design */
1937 tny_folder_refresh_async (folder,
1939 on_refresh_folder_status_update,
1945 * It's used by the mail operation queue to notify the observers
1946 * attached to that signal that the operation finished. We need to use
1947 * that because tinymail does not give us the progress of a given
1948 * operation when it finishes (it directly calls the operation
1952 modest_mail_operation_notify_end (ModestMailOperation *self)
1954 ModestMailOperationState *state;
1956 /* Notify the observers about the mail opertation end */
1957 state = modest_mail_operation_clone_state (self);
1958 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1959 g_slice_free (ModestMailOperationState, state);
1961 /* Notify the queue */
1962 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);