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 /* cancel current operation in account */
335 tny_account_cancel (priv->account);
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;
777 ModestTnySendQueue *send_queue;
779 info = (UpdateAccountInfo *) thr_user_data;
780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
782 /* Get account and set it into mail_operation */
783 priv->account = g_object_ref (info->account);
785 /* Get all the folders We can do it synchronously because
786 we're already running in a different thread than the UI */
787 all_folders = tny_simple_list_new ();
788 query = tny_folder_store_query_new ();
789 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
790 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
795 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
799 iter = tny_list_create_iterator (all_folders);
800 while (!tny_iterator_is_done (iter)) {
801 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
803 recurse_folders (folder, query, all_folders);
804 tny_iterator_next (iter);
806 g_object_unref (G_OBJECT (iter));
808 /* Update status and notify. We need to call the notification
809 with a source functopm in order to call it from the main
810 loop. We need that in order not to get into trouble with
811 Gtk+. We use a timeout in order to provide more status
812 information, because the sync tinymail call does not
813 provide it for the moment */
814 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
816 /* Refresh folders */
817 new_headers = g_ptr_array_new ();
818 iter = tny_list_create_iterator (all_folders);
819 while (!tny_iterator_is_done (iter) && !priv->error) {
821 InternalFolderObserver *observer;
822 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
824 /* Refresh the folder */
825 observer = g_object_new (internal_folder_observer_get_type (), NULL);
826 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
827 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
829 /* If the retrieve type is headers only do nothing more */
830 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
831 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
834 iter = tny_list_create_iterator (observer->new_headers);
835 while (!tny_iterator_is_done (iter)) {
836 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
837 /* Apply per-message size limits */
838 if (tny_header_get_message_size (header) < info->max_size)
839 g_ptr_array_add (new_headers, g_object_ref (header));
841 g_object_unref (header);
842 tny_iterator_next (iter);
844 g_object_unref (iter);
846 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
847 g_object_unref (observer);
850 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
852 g_object_unref (G_OBJECT (folder));
853 tny_iterator_next (iter);
855 g_object_unref (G_OBJECT (iter));
856 g_source_remove (timeout);
858 if (new_headers->len > 0) {
862 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
864 /* Apply message count limit */
865 /* TODO if the number of messages exceeds the maximum, ask the
866 user to download them all */
868 priv->total = MIN (new_headers->len, info->retrieve_limit);
869 while ((msg_num < priv->total)) {
871 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
872 TnyFolder *folder = tny_header_get_folder (header);
873 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
874 ModestMailOperationState *state;
878 /* We can not just use the mail operation because the
879 values of done and total could change before the
881 state = modest_mail_operation_clone_state (info->mail_op);
882 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
883 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
884 pair, (GDestroyNotify) modest_pair_free);
886 g_object_unref (msg);
887 g_object_unref (folder);
891 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
892 g_ptr_array_free (new_headers, FALSE);
896 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
899 if (priv->account != NULL)
900 g_object_unref (priv->account);
901 priv->account = g_object_ref (info->transport_account);
903 send_queue = modest_runtime_get_send_queue (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_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
910 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
911 "cannot create a send queue for %s\n",
912 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
913 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
916 /* Check if the operation was a success */
918 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
920 /* Update the last updated key */
921 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
922 tny_account_get_id (TNY_ACCOUNT (info->account)),
923 MODEST_ACCOUNT_LAST_UPDATED,
929 /* Notify about operation end. Note that the info could be
930 freed before this idle happens, but the mail operation will
932 g_idle_add (notify_update_account_queue, info->mail_op);
935 g_object_unref (query);
936 g_object_unref (all_folders);
937 g_object_unref (info->account);
938 g_object_unref (info->transport_account);
939 g_free (info->retrieve_type);
940 g_slice_free (UpdateAccountInfo, info);
946 modest_mail_operation_update_account (ModestMailOperation *self,
947 const gchar *account_name)
950 UpdateAccountInfo *info;
951 ModestMailOperationPrivate *priv;
952 ModestAccountMgr *mgr;
953 TnyStoreAccount *modest_account;
954 TnyTransportAccount *transport_account;
956 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
957 g_return_val_if_fail (account_name, FALSE);
959 /* Init mail operation. Set total and done to 0, and do not
960 update them, this way the progress objects will know that
961 we have no clue about the number of the objects */
962 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
965 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
967 /* Get the Modest account */
968 modest_account = (TnyStoreAccount *)
969 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
971 TNY_ACCOUNT_TYPE_STORE);
973 if (!modest_account) {
974 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
975 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
976 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
977 "cannot get tny store account for %s\n", account_name);
978 modest_mail_operation_notify_end (self);
982 /* Get the transport account, we can not do it in the thread
983 due to some problems with dbus */
984 transport_account = (TnyTransportAccount *)
985 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
987 if (!transport_account) {
988 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
990 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
991 "cannot get tny transport account for %s\n", account_name);
992 modest_mail_operation_notify_end (self);
996 /* Create the helper object */
997 info = g_slice_new (UpdateAccountInfo);
998 info->mail_op = self;
999 info->account = modest_account;
1000 info->transport_account = transport_account;
1002 /* Get the message size limit */
1003 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1004 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1005 if (info->max_size == 0)
1006 info->max_size = G_MAXINT;
1008 info->max_size = info->max_size * KB;
1010 /* Get per-account retrieval type */
1011 mgr = modest_runtime_get_account_mgr ();
1012 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1013 MODEST_ACCOUNT_RETRIEVE, FALSE);
1015 /* Get per-account message amount retrieval limit */
1016 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1017 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1018 if (info->retrieve_limit == 0)
1019 info->retrieve_limit = G_MAXINT;
1021 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1026 /* ******************************************************************* */
1027 /* ************************** STORE ACTIONS ************************* */
1028 /* ******************************************************************* */
1032 modest_mail_operation_create_folder (ModestMailOperation *self,
1033 TnyFolderStore *parent,
1036 ModestMailOperationPrivate *priv;
1037 TnyFolder *new_folder = NULL;
1039 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1040 g_return_val_if_fail (name, NULL);
1042 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1045 if (TNY_IS_FOLDER (parent)) {
1046 /* Check folder rules */
1047 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1048 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1049 /* Set status failed and set an error */
1050 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1051 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1052 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1053 _("mail_in_ui_folder_create_error"));
1058 /* Create the folder */
1059 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1060 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1062 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1065 /* Notify about operation end */
1066 modest_mail_operation_notify_end (self);
1072 modest_mail_operation_remove_folder (ModestMailOperation *self,
1074 gboolean remove_to_trash)
1076 TnyAccount *account;
1077 ModestMailOperationPrivate *priv;
1078 ModestTnyFolderRules rules;
1080 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1081 g_return_if_fail (TNY_IS_FOLDER (folder));
1083 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1085 /* Check folder rules */
1086 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1087 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1088 /* Set status failed and set an error */
1089 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1090 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1091 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1092 _("mail_in_ui_folder_delete_error"));
1096 /* Get the account */
1097 account = tny_folder_get_account (folder);
1098 priv->account = g_object_ref(account);
1100 /* Delete folder or move to trash */
1101 if (remove_to_trash) {
1102 TnyFolder *trash_folder = NULL;
1103 trash_folder = modest_tny_account_get_special_folder (account,
1104 TNY_FOLDER_TYPE_TRASH);
1105 /* TODO: error_handling */
1106 modest_mail_operation_xfer_folder (self, folder,
1107 TNY_FOLDER_STORE (trash_folder), TRUE);
1109 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1111 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1112 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1115 g_object_unref (G_OBJECT (parent));
1117 g_object_unref (G_OBJECT (account));
1120 /* Notify about operation end */
1121 modest_mail_operation_notify_end (self);
1125 transfer_folder_status_cb (GObject *obj,
1129 ModestMailOperation *self;
1130 ModestMailOperationPrivate *priv;
1131 ModestMailOperationState *state;
1133 g_return_if_fail (status != NULL);
1134 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1136 self = MODEST_MAIL_OPERATION (user_data);
1137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1139 if ((status->position == 1) && (status->of_total == 100))
1142 priv->done = status->position;
1143 priv->total = status->of_total;
1145 state = modest_mail_operation_clone_state (self);
1146 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1147 g_slice_free (ModestMailOperationState, state);
1152 transfer_folder_cb (TnyFolder *folder,
1153 TnyFolderStore *into,
1155 TnyFolder *new_folder, GError **err,
1158 ModestMailOperation *self = NULL;
1159 ModestMailOperationPrivate *priv = NULL;
1161 self = MODEST_MAIL_OPERATION (user_data);
1163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1166 priv->error = g_error_copy (*err);
1168 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1169 } else if (cancelled) {
1170 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1171 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1172 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1173 _("Transference of %s was cancelled."),
1174 tny_folder_get_name (folder));
1177 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1181 g_object_unref (folder);
1182 g_object_unref (into);
1183 if (new_folder != NULL)
1184 g_object_unref (new_folder);
1186 /* Notify about operation end */
1187 modest_mail_operation_notify_end (self);
1191 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1193 TnyFolderStore *parent,
1194 gboolean delete_original)
1196 ModestMailOperationPrivate *priv = NULL;
1197 ModestTnyFolderRules parent_rules, rules;
1199 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1200 g_return_if_fail (TNY_IS_FOLDER (folder));
1201 g_return_if_fail (TNY_IS_FOLDER (parent));
1203 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1205 /* Get account and set it into mail_operation */
1206 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1207 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1209 /* Get folder rules */
1210 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1211 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1213 if (!TNY_IS_FOLDER_STORE (parent)) {
1217 /* The moveable restriction is applied also to copy operation */
1218 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1219 /* Set status failed and set an error */
1220 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1221 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1222 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1223 _("mail_in_ui_folder_move_target_error"));
1225 /* Notify the queue */
1226 modest_mail_operation_notify_end (self);
1227 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1228 /* Set status failed and set an error */
1229 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1230 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1231 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1232 _("FIXME: parent folder does not accept new folders"));
1234 /* Notify the queue */
1235 modest_mail_operation_notify_end (self);
1237 /* Pick references for async calls */
1238 g_object_ref (folder);
1239 g_object_ref (parent);
1241 /* Move/Copy folder */
1242 tny_folder_copy_async (folder,
1244 tny_folder_get_name (folder),
1247 transfer_folder_status_cb,
1253 modest_mail_operation_rename_folder (ModestMailOperation *self,
1257 ModestMailOperationPrivate *priv;
1258 ModestTnyFolderRules rules;
1260 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1261 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1262 g_return_if_fail (name);
1264 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1266 /* Get account and set it into mail_operation */
1267 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1269 /* Check folder rules */
1270 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1271 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1272 /* Set status failed and set an error */
1273 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1274 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1275 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1276 _("FIXME: unable to rename"));
1278 /* Notify about operation end */
1279 modest_mail_operation_notify_end (self);
1281 /* Rename. Camel handles folder subscription/unsubscription */
1282 TnyFolderStore *into;
1284 into = tny_folder_get_folder_store (folder);
1285 tny_folder_copy_async (folder, into, name, TRUE,
1287 transfer_folder_status_cb,
1290 g_object_unref (into);
1295 /* ******************************************************************* */
1296 /* ************************** MSG ACTIONS ************************* */
1297 /* ******************************************************************* */
1299 void modest_mail_operation_get_msg (ModestMailOperation *self,
1301 GetMsgAsyncUserCallback user_callback,
1304 GetMsgAsyncHelper *helper = NULL;
1306 ModestMailOperationPrivate *priv;
1308 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1309 g_return_if_fail (TNY_IS_HEADER (header));
1311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1312 folder = tny_header_get_folder (header);
1314 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1316 /* Get message from folder */
1318 /* Get account and set it into mail_operation */
1319 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1321 helper = g_slice_new0 (GetMsgAsyncHelper);
1322 helper->mail_op = self;
1323 helper->user_callback = user_callback;
1324 helper->pending_ops = 1;
1325 helper->user_data = user_data;
1327 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1329 g_object_unref (G_OBJECT (folder));
1331 /* Set status failed and set an error */
1332 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1333 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1334 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1335 _("Error trying to get a message. No folder found for header"));
1337 /* Notify the queue */
1338 modest_mail_operation_notify_end (self);
1343 get_msg_cb (TnyFolder *folder,
1349 GetMsgAsyncHelper *helper = NULL;
1350 ModestMailOperation *self = NULL;
1351 ModestMailOperationPrivate *priv = NULL;
1353 helper = (GetMsgAsyncHelper *) user_data;
1354 g_return_if_fail (helper != NULL);
1355 self = helper->mail_op;
1356 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1359 helper->pending_ops--;
1361 /* Check errors and cancel */
1363 priv->error = g_error_copy (*error);
1364 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1368 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1369 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1370 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1371 _("Error trying to refresh the contents of %s"),
1372 tny_folder_get_name (folder));
1376 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1378 /* If user defined callback function was defined, call it */
1379 if (helper->user_callback) {
1380 helper->user_callback (self, NULL, msg, helper->user_data);
1385 if (helper->pending_ops == 0) {
1386 g_slice_free (GetMsgAsyncHelper, helper);
1388 /* Notify about operation end */
1389 modest_mail_operation_notify_end (self);
1394 get_msg_status_cb (GObject *obj,
1398 GetMsgAsyncHelper *helper = NULL;
1399 ModestMailOperation *self;
1400 ModestMailOperationPrivate *priv;
1401 ModestMailOperationState *state;
1403 g_return_if_fail (status != NULL);
1404 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1406 helper = (GetMsgAsyncHelper *) user_data;
1407 g_return_if_fail (helper != NULL);
1409 self = helper->mail_op;
1410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1412 if ((status->position == 1) && (status->of_total == 100))
1418 state = modest_mail_operation_clone_state (self);
1419 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1420 g_slice_free (ModestMailOperationState, state);
1423 /****************************************************/
1425 ModestMailOperation *mail_op;
1427 GetMsgAsyncUserCallback user_callback;
1429 GDestroyNotify notify;
1433 GetMsgAsyncUserCallback user_callback;
1437 ModestMailOperation *mail_op;
1438 } NotifyGetMsgsInfo;
1442 * Used by get_msgs_full_thread to call the user_callback for each
1443 * message that has been read
1446 notify_get_msgs_full (gpointer data)
1448 NotifyGetMsgsInfo *info;
1450 info = (NotifyGetMsgsInfo *) data;
1452 /* Call the user callback */
1453 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1455 g_slice_free (NotifyGetMsgsInfo, info);
1461 * Used by get_msgs_full_thread to free al the thread resources and to
1462 * call the destroy function for the passed user_data
1465 get_msgs_full_destroyer (gpointer data)
1467 GetFullMsgsInfo *info;
1469 info = (GetFullMsgsInfo *) data;
1472 info->notify (info->user_data);
1475 g_object_unref (info->headers);
1476 g_slice_free (GetFullMsgsInfo, info);
1482 get_msgs_full_thread (gpointer thr_user_data)
1484 GetFullMsgsInfo *info;
1485 ModestMailOperationPrivate *priv = NULL;
1486 TnyIterator *iter = NULL;
1488 info = (GetFullMsgsInfo *) thr_user_data;
1489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1491 iter = tny_list_create_iterator (info->headers);
1492 while (!tny_iterator_is_done (iter)) {
1496 header = TNY_HEADER (tny_iterator_get_current (iter));
1497 folder = tny_header_get_folder (header);
1499 /* Get message from folder */
1502 /* The callback will call it per each header */
1503 msg = tny_folder_get_msg (folder, header, &(priv->error));
1506 ModestMailOperationState *state;
1511 /* notify progress */
1512 state = modest_mail_operation_clone_state (info->mail_op);
1513 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1514 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1515 pair, (GDestroyNotify) modest_pair_free);
1517 /* The callback is the responsible for
1518 freeing the message */
1519 if (info->user_callback) {
1520 NotifyGetMsgsInfo *info_notify;
1521 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1522 info_notify->user_callback = info->user_callback;
1523 info_notify->mail_op = info->mail_op;
1524 info_notify->header = g_object_ref (header);
1525 info_notify->msg = g_object_ref (msg);
1526 info_notify->user_data = info->user_data;
1527 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1528 notify_get_msgs_full,
1531 g_object_unref (msg);
1534 /* Set status failed and set an error */
1535 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1536 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1537 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1538 "Error trying to get a message. No folder found for header");
1540 g_object_unref (header);
1541 tny_iterator_next (iter);
1544 /* Set operation status */
1545 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1546 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1548 /* Notify about operation end */
1549 g_idle_add (notify_update_account_queue, info->mail_op);
1551 /* Free thread resources. Will be called after all previous idles */
1552 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1558 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1559 TnyList *header_list,
1560 GetMsgAsyncUserCallback user_callback,
1562 GDestroyNotify notify)
1564 TnyHeader *header = NULL;
1565 TnyFolder *folder = NULL;
1567 ModestMailOperationPrivate *priv = NULL;
1568 GetFullMsgsInfo *info = NULL;
1569 gboolean size_ok = TRUE;
1571 TnyIterator *iter = NULL;
1573 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1575 /* Init mail operation */
1576 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1577 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1579 priv->total = tny_list_get_length(header_list);
1581 /* Get account and set it into mail_operation */
1582 if (tny_list_get_length (header_list) > 1) {
1583 iter = tny_list_create_iterator (header_list);
1584 header = TNY_HEADER (tny_iterator_get_current (iter));
1585 folder = tny_header_get_folder (header);
1586 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1587 g_object_unref (header);
1588 g_object_unref (folder);
1591 /* Get msg size limit */
1592 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1593 MODEST_CONF_MSG_SIZE_LIMIT,
1596 g_clear_error (&(priv->error));
1597 max_size = G_MAXINT;
1599 max_size = max_size * KB;
1602 /* Check message size limits. If there is only one message
1603 always retrieve it */
1605 while (!tny_iterator_is_done (iter) && size_ok) {
1606 header = TNY_HEADER (tny_iterator_get_current (iter));
1607 if (tny_header_get_message_size (header) >= max_size)
1609 g_object_unref (header);
1610 tny_iterator_next (iter);
1612 g_object_unref (iter);
1616 /* Create the info */
1617 info = g_slice_new0 (GetFullMsgsInfo);
1618 info->mail_op = self;
1619 info->user_callback = user_callback;
1620 info->user_data = user_data;
1621 info->headers = g_object_ref (header_list);
1622 info->notify = notify;
1624 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1626 /* Set status failed and set an error */
1627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1628 /* FIXME: the error msg is different for pop */
1629 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1630 MODEST_MAIL_OPERATION_ERROR_SIZE_LIMIT,
1631 _("emev_ni_ui_imap_msg_size_exceed_error"));
1632 /* Remove from queue and free resources */
1633 modest_mail_operation_notify_end (self);
1641 modest_mail_operation_remove_msg (ModestMailOperation *self,
1643 gboolean remove_to_trash)
1646 ModestMailOperationPrivate *priv;
1648 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1649 g_return_if_fail (TNY_IS_HEADER (header));
1651 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1652 folder = tny_header_get_folder (header);
1654 /* Get account and set it into mail_operation */
1655 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1657 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1659 /* Delete or move to trash */
1660 if (remove_to_trash) {
1661 TnyFolder *trash_folder;
1662 TnyStoreAccount *store_account;
1664 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1665 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1666 TNY_FOLDER_TYPE_TRASH);
1671 headers = tny_simple_list_new ();
1672 tny_list_append (headers, G_OBJECT (header));
1673 g_object_unref (header);
1676 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1677 g_object_unref (headers);
1678 /* g_object_unref (trash_folder); */
1680 ModestMailOperationPrivate *priv;
1682 /* Set status failed and set an error */
1683 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1684 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1685 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1686 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1687 _("Error trying to delete a message. Trash folder not found"));
1690 g_object_unref (G_OBJECT (store_account));
1692 tny_folder_remove_msg (folder, header, &(priv->error));
1694 tny_folder_sync(folder, TRUE, &(priv->error));
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1701 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1704 g_object_unref (G_OBJECT (folder));
1706 /* Notify about operation end */
1707 modest_mail_operation_notify_end (self);
1711 transfer_msgs_status_cb (GObject *obj,
1715 XFerMsgAsyncHelper *helper = NULL;
1716 ModestMailOperation *self;
1717 ModestMailOperationPrivate *priv;
1718 ModestMailOperationState *state;
1721 g_return_if_fail (status != NULL);
1722 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1724 helper = (XFerMsgAsyncHelper *) user_data;
1725 g_return_if_fail (helper != NULL);
1727 self = helper->mail_op;
1728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1730 if ((status->position == 1) && (status->of_total == 100))
1733 priv->done = status->position;
1734 priv->total = status->of_total;
1736 state = modest_mail_operation_clone_state (self);
1737 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1738 g_slice_free (ModestMailOperationState, state);
1743 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1745 XFerMsgAsyncHelper *helper;
1746 ModestMailOperation *self;
1747 ModestMailOperationPrivate *priv;
1749 helper = (XFerMsgAsyncHelper *) user_data;
1750 self = helper->mail_op;
1752 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1755 priv->error = g_error_copy (*err);
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1758 } else if (cancelled) {
1759 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1760 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1761 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1762 _("Error trying to refresh the contents of %s"),
1763 tny_folder_get_name (folder));
1766 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1769 /* If user defined callback function was defined, call it */
1770 if (helper->user_callback) {
1771 helper->user_callback (priv->source, helper->user_data);
1775 g_object_unref (helper->headers);
1776 g_object_unref (helper->dest_folder);
1777 g_object_unref (helper->mail_op);
1778 g_slice_free (XFerMsgAsyncHelper, helper);
1779 g_object_unref (folder);
1781 /* Notify about operation end */
1782 modest_mail_operation_notify_end (self);
1786 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1789 gboolean delete_original,
1790 XferMsgsAsynUserCallback user_callback,
1793 ModestMailOperationPrivate *priv;
1795 TnyFolder *src_folder;
1796 XFerMsgAsyncHelper *helper;
1798 ModestTnyFolderRules rules;
1800 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1801 g_return_if_fail (TNY_IS_LIST (headers));
1802 g_return_if_fail (TNY_IS_FOLDER (folder));
1804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1807 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1809 /* Apply folder rules */
1810 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1812 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1813 /* Set status failed and set an error */
1814 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1815 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1816 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1817 _("FIXME: folder does not accept msgs"));
1818 /* Notify the queue */
1819 modest_mail_operation_notify_end (self);
1823 /* Create the helper */
1824 helper = g_slice_new0 (XFerMsgAsyncHelper);
1825 helper->mail_op = g_object_ref(self);
1826 helper->dest_folder = g_object_ref(folder);
1827 helper->headers = g_object_ref(headers);
1828 helper->user_callback = user_callback;
1829 helper->user_data = user_data;
1831 /* Get source folder */
1832 iter = tny_list_create_iterator (headers);
1833 header = TNY_HEADER (tny_iterator_get_current (iter));
1834 src_folder = tny_header_get_folder (header);
1835 g_object_unref (header);
1836 g_object_unref (iter);
1838 /* Get account and set it into mail_operation */
1839 priv->account = tny_folder_get_account (src_folder);
1841 /* Transfer messages */
1842 tny_folder_transfer_msgs_async (src_folder,
1847 transfer_msgs_status_cb,
1853 on_refresh_folder (TnyFolder *folder,
1858 ModestMailOperation *self;
1859 ModestMailOperationPrivate *priv;
1861 self = MODEST_MAIL_OPERATION (user_data);
1862 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1865 priv->error = g_error_copy (*error);
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1871 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1872 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1873 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1874 _("Error trying to refresh the contents of %s"),
1875 tny_folder_get_name (folder));
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1883 g_object_unref (folder);
1885 /* Notify about operation end */
1886 modest_mail_operation_notify_end (self);
1890 on_refresh_folder_status_update (GObject *obj,
1894 ModestMailOperation *self;
1895 ModestMailOperationPrivate *priv;
1896 ModestMailOperationState *state;
1898 g_return_if_fail (status != NULL);
1899 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1901 self = MODEST_MAIL_OPERATION (user_data);
1902 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1904 priv->done = status->position;
1905 priv->total = status->of_total;
1907 state = modest_mail_operation_clone_state (self);
1908 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1909 g_slice_free (ModestMailOperationState, state);
1913 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1916 ModestMailOperationPrivate *priv;
1918 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1920 /* Pick a reference */
1921 g_object_ref (folder);
1923 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1925 /* Get account and set it into mail_operation */
1926 priv->account = tny_folder_get_account (folder);
1928 /* Refresh the folder. TODO: tinymail could issue a status
1929 updates before the callback call then this could happen. We
1930 must review the design */
1931 tny_folder_refresh_async (folder,
1933 on_refresh_folder_status_update,
1939 * It's used by the mail operation queue to notify the observers
1940 * attached to that signal that the operation finished. We need to use
1941 * that because tinymail does not give us the progress of a given
1942 * operation when it finishes (it directly calls the operation
1946 modest_mail_operation_notify_end (ModestMailOperation *self)
1948 ModestMailOperationState *state;
1950 /* Notify the observers about the mail opertation end */
1951 state = modest_mail_operation_clone_state (self);
1952 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1953 g_slice_free (ModestMailOperationState, state);
1955 /* Notify the queue */
1956 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);