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 /* printf("DEBUG: %s: header subject=%s\n",
613 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
615 tny_list_prepend (TNY_LIST (user_data),
616 g_object_ref (G_OBJECT (header)));
619 /* This is the method that looks for new messages in a folder */
621 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
623 InternalFolderObserver *derived = (InternalFolderObserver *)self;
625 TnyFolderChangeChanged changed;
627 changed = tny_folder_change_get_changed (change);
629 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
632 /* Get added headers */
633 list = tny_simple_list_new ();
634 tny_folder_change_get_added_headers (change, list);
636 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
637 * __FUNCTION__, tny_list_get_length(list));
640 /* Add them to the folder observer */
641 tny_list_foreach (list, foreach_add_item,
642 derived->new_headers);
644 g_object_unref (G_OBJECT (list));
649 internal_folder_observer_init (InternalFolderObserver *self)
651 self->new_headers = tny_simple_list_new ();
654 internal_folder_observer_finalize (GObject *object)
656 InternalFolderObserver *self;
658 self = (InternalFolderObserver *) object;
659 g_object_unref (self->new_headers);
661 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
664 tny_folder_observer_init (TnyFolderObserverIface *iface)
666 iface->update_func = internal_folder_observer_update;
669 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
671 GObjectClass *object_class;
673 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
674 object_class = (GObjectClass*) klass;
675 object_class->finalize = internal_folder_observer_finalize;
681 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
684 TnyList *folders = tny_simple_list_new ();
686 tny_folder_store_get_folders (store, folders, query, NULL);
687 iter = tny_list_create_iterator (folders);
689 while (!tny_iterator_is_done (iter)) {
691 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
693 tny_list_prepend (all_folders, G_OBJECT (folder));
694 recurse_folders (folder, query, all_folders);
695 g_object_unref (G_OBJECT (folder));
697 tny_iterator_next (iter);
699 g_object_unref (G_OBJECT (iter));
700 g_object_unref (G_OBJECT (folders));
704 * Issues the "progress-changed" signal. The timer won't be removed,
705 * so you must call g_source_remove to stop the signal emission
708 idle_notify_progress (gpointer data)
710 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
711 ModestMailOperationState *state;
713 state = modest_mail_operation_clone_state (mail_op);
714 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
715 g_slice_free (ModestMailOperationState, state);
721 * Issues the "progress-changed" signal and removes the timer. It uses
722 * a lock to ensure that the progress information of the mail
723 * operation is not modified while there are notifications pending
726 idle_notify_progress_once (gpointer data)
730 pair = (ModestPair *) data;
732 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
734 /* Free the state and the reference to the mail operation */
735 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
736 g_object_unref (pair->first);
742 * Used by update_account_thread to notify the queue from the main
743 * loop. We call it inside an idle call to achieve that
746 notify_update_account_queue (gpointer data)
748 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
750 modest_mail_operation_notify_end (mail_op);
751 g_object_unref (mail_op);
757 compare_headers_by_date (gconstpointer a,
760 TnyHeader **header1, **header2;
763 header1 = (TnyHeader **) a;
764 header2 = (TnyHeader **) b;
766 sent1 = tny_header_get_date_sent (*header1);
767 sent2 = tny_header_get_date_sent (*header2);
769 /* We want the most recent ones (greater time_t) at the
778 update_account_thread (gpointer thr_user_data)
780 UpdateAccountInfo *info;
781 TnyList *all_folders = NULL;
782 GPtrArray *new_headers;
783 TnyIterator *iter = NULL;
784 TnyFolderStoreQuery *query = NULL;
785 ModestMailOperationPrivate *priv;
786 ModestTnySendQueue *send_queue;
788 info = (UpdateAccountInfo *) thr_user_data;
789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
791 /* Get account and set it into mail_operation */
792 priv->account = g_object_ref (info->account);
794 /* Get all the folders. We can do it synchronously because
795 we're already running in a different thread than the UI */
796 all_folders = tny_simple_list_new ();
797 query = tny_folder_store_query_new ();
798 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
799 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
804 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
808 iter = tny_list_create_iterator (all_folders);
809 while (!tny_iterator_is_done (iter)) {
810 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
812 recurse_folders (folder, query, all_folders);
813 tny_iterator_next (iter);
815 g_object_unref (G_OBJECT (iter));
817 /* Update status and notify. We need to call the notification
818 with a source function in order to call it from the main
819 loop. We need that in order not to get into trouble with
820 Gtk+. We use a timeout in order to provide more status
821 information, because the sync tinymail call does not
822 provide it for the moment */
823 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
825 /* Refresh folders */
826 new_headers = g_ptr_array_new ();
827 iter = tny_list_create_iterator (all_folders);
828 while (!tny_iterator_is_done (iter) && !priv->error) {
830 InternalFolderObserver *observer;
831 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
833 /* Refresh the folder */
834 /* Our observer receives notification of new emails during folder refreshes,
835 * so we can use observer->new_headers.
836 * TODO: This does not seem to be providing accurate numbers.
837 * Possibly the observer is notified asynchronously.
839 observer = g_object_new (internal_folder_observer_get_type (), NULL);
840 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
842 /* This gets the status information (headers) from the server.
843 * We use the blocking version, because we are already in a separate
846 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
848 /* If the retrieve type is headers only do nothing more */
849 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
850 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
853 iter = tny_list_create_iterator (observer->new_headers);
854 while (!tny_iterator_is_done (iter)) {
855 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
856 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
857 * __FUNCTION__, tny_account_get_id (priv->account),
858 * tny_header_get_subject (header));
861 /* Apply per-message size limits */
862 if (tny_header_get_message_size (header) < info->max_size)
863 g_ptr_array_add (new_headers, g_object_ref (header));
865 g_object_unref (header);
866 tny_iterator_next (iter);
868 g_object_unref (iter);
871 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
872 g_object_unref (observer);
876 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
878 g_object_unref (G_OBJECT (folder));
879 tny_iterator_next (iter);
881 g_object_unref (G_OBJECT (iter));
882 g_source_remove (timeout);
884 if (new_headers->len > 0) {
888 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
890 /* Apply message count limit */
891 /* If the number of messages exceeds the maximum, ask the
892 * user to download them all,
893 * as per the UI spec "Retrieval Limits" section in 4.4:
895 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
896 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
897 if (new_headers->len > info->retrieve_limit) {
898 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
899 * with 'Get all' and 'Newest only' buttons. */
900 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
901 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
902 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
903 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
904 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
909 priv->total = MIN (new_headers->len, info->retrieve_limit);
910 while (msg_num < priv->total) {
912 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
913 TnyFolder *folder = tny_header_get_folder (header);
914 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
915 ModestMailOperationState *state;
919 /* We can not just use the mail operation because the
920 values of done and total could change before the
922 state = modest_mail_operation_clone_state (info->mail_op);
923 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
924 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
925 pair, (GDestroyNotify) modest_pair_free);
927 g_object_unref (msg);
928 g_object_unref (folder);
932 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
933 g_ptr_array_free (new_headers, FALSE);
937 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
940 if (priv->account != NULL)
941 g_object_unref (priv->account);
942 priv->account = g_object_ref (info->transport_account);
944 send_queue = modest_runtime_get_send_queue (info->transport_account);
946 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
947 modest_tny_send_queue_try_to_send (send_queue);
948 g_source_remove (timeout);
950 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
951 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
952 "cannot create a send queue for %s\n",
953 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
957 /* Check if the operation was a success */
959 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
961 /* Update the last updated key */
962 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
963 tny_account_get_id (TNY_ACCOUNT (info->account)),
964 MODEST_ACCOUNT_LAST_UPDATED,
970 /* Notify about operation end. Note that the info could be
971 freed before this idle happens, but the mail operation will
973 g_idle_add (notify_update_account_queue, info->mail_op);
976 g_object_unref (query);
977 g_object_unref (all_folders);
978 g_object_unref (info->account);
979 g_object_unref (info->transport_account);
980 g_free (info->retrieve_type);
981 g_slice_free (UpdateAccountInfo, info);
987 modest_mail_operation_update_account (ModestMailOperation *self,
988 const gchar *account_name)
991 UpdateAccountInfo *info;
992 ModestMailOperationPrivate *priv;
993 ModestAccountMgr *mgr;
994 TnyStoreAccount *modest_account;
995 TnyTransportAccount *transport_account;
997 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
998 g_return_val_if_fail (account_name, FALSE);
1000 /* Init mail operation. Set total and done to 0, and do not
1001 update them, this way the progress objects will know that
1002 we have no clue about the number of the objects */
1003 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1006 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1008 /* Get the Modest account */
1009 modest_account = (TnyStoreAccount *)
1010 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
1012 TNY_ACCOUNT_TYPE_STORE);
1014 if (!modest_account) {
1015 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1016 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1017 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1018 "cannot get tny store account for %s\n", account_name);
1019 modest_mail_operation_notify_end (self);
1023 /* Get the transport account, we can not do it in the thread
1024 due to some problems with dbus */
1025 transport_account = (TnyTransportAccount *)
1026 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1028 if (!transport_account) {
1029 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1030 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1031 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1032 "cannot get tny transport account for %s\n", account_name);
1033 modest_mail_operation_notify_end (self);
1037 /* Create the helper object */
1038 info = g_slice_new (UpdateAccountInfo);
1039 info->mail_op = self;
1040 info->account = modest_account;
1041 info->transport_account = transport_account;
1043 /* Get the message size limit */
1044 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1045 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1046 if (info->max_size == 0)
1047 info->max_size = G_MAXINT;
1049 info->max_size = info->max_size * KB;
1051 /* Get per-account retrieval type */
1052 mgr = modest_runtime_get_account_mgr ();
1053 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1054 MODEST_ACCOUNT_RETRIEVE, FALSE);
1056 /* Get per-account message amount retrieval limit */
1057 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1058 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1059 if (info->retrieve_limit == 0)
1060 info->retrieve_limit = G_MAXINT;
1062 printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit);
1064 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1069 /* ******************************************************************* */
1070 /* ************************** STORE ACTIONS ************************* */
1071 /* ******************************************************************* */
1075 modest_mail_operation_create_folder (ModestMailOperation *self,
1076 TnyFolderStore *parent,
1079 ModestMailOperationPrivate *priv;
1080 TnyFolder *new_folder = NULL;
1082 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1083 g_return_val_if_fail (name, NULL);
1085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1088 if (TNY_IS_FOLDER (parent)) {
1089 /* Check folder rules */
1090 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1091 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1092 /* Set status failed and set an error */
1093 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1094 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1095 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1096 _("mail_in_ui_folder_create_error"));
1101 /* Create the folder */
1102 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1103 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1105 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1108 /* Notify about operation end */
1109 modest_mail_operation_notify_end (self);
1115 modest_mail_operation_remove_folder (ModestMailOperation *self,
1117 gboolean remove_to_trash)
1119 TnyAccount *account;
1120 ModestMailOperationPrivate *priv;
1121 ModestTnyFolderRules rules;
1123 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1124 g_return_if_fail (TNY_IS_FOLDER (folder));
1126 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1128 /* Check folder rules */
1129 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1130 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1131 /* Set status failed and set an error */
1132 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1133 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1134 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1135 _("mail_in_ui_folder_delete_error"));
1139 /* Get the account */
1140 account = tny_folder_get_account (folder);
1141 priv->account = g_object_ref(account);
1143 /* Delete folder or move to trash */
1144 if (remove_to_trash) {
1145 TnyFolder *trash_folder = NULL;
1146 trash_folder = modest_tny_account_get_special_folder (account,
1147 TNY_FOLDER_TYPE_TRASH);
1148 /* TODO: error_handling */
1149 modest_mail_operation_xfer_folder (self, folder,
1150 TNY_FOLDER_STORE (trash_folder), TRUE);
1152 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1154 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1155 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1158 g_object_unref (G_OBJECT (parent));
1160 g_object_unref (G_OBJECT (account));
1163 /* Notify about operation end */
1164 modest_mail_operation_notify_end (self);
1168 transfer_folder_status_cb (GObject *obj,
1172 ModestMailOperation *self;
1173 ModestMailOperationPrivate *priv;
1174 ModestMailOperationState *state;
1176 g_return_if_fail (status != NULL);
1177 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1179 self = MODEST_MAIL_OPERATION (user_data);
1180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1182 if ((status->position == 1) && (status->of_total == 100))
1185 priv->done = status->position;
1186 priv->total = status->of_total;
1188 state = modest_mail_operation_clone_state (self);
1189 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1190 g_slice_free (ModestMailOperationState, state);
1195 transfer_folder_cb (TnyFolder *folder,
1196 TnyFolderStore *into,
1198 TnyFolder *new_folder, GError **err,
1201 ModestMailOperation *self = NULL;
1202 ModestMailOperationPrivate *priv = NULL;
1204 self = MODEST_MAIL_OPERATION (user_data);
1206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1209 priv->error = g_error_copy (*err);
1211 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1212 } else if (cancelled) {
1213 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1214 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1215 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1216 _("Transference of %s was cancelled."),
1217 tny_folder_get_name (folder));
1220 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1224 g_object_unref (folder);
1225 g_object_unref (into);
1226 if (new_folder != NULL)
1227 g_object_unref (new_folder);
1229 /* Notify about operation end */
1230 modest_mail_operation_notify_end (self);
1234 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1236 TnyFolderStore *parent,
1237 gboolean delete_original)
1239 ModestMailOperationPrivate *priv = NULL;
1240 ModestTnyFolderRules parent_rules, rules;
1242 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1243 g_return_if_fail (TNY_IS_FOLDER (folder));
1244 g_return_if_fail (TNY_IS_FOLDER (parent));
1246 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1248 /* Get account and set it into mail_operation */
1249 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1252 /* Get folder rules */
1253 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1254 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1256 if (!TNY_IS_FOLDER_STORE (parent)) {
1260 /* The moveable restriction is applied also to copy operation */
1261 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1262 /* Set status failed and set an error */
1263 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1264 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1265 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1266 _("mail_in_ui_folder_move_target_error"));
1268 /* Notify the queue */
1269 modest_mail_operation_notify_end (self);
1270 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1271 /* Set status failed and set an error */
1272 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1273 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1274 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1275 _("FIXME: parent folder does not accept new folders"));
1277 /* Notify the queue */
1278 modest_mail_operation_notify_end (self);
1280 /* Pick references for async calls */
1281 g_object_ref (folder);
1282 g_object_ref (parent);
1284 /* Move/Copy folder */
1285 tny_folder_copy_async (folder,
1287 tny_folder_get_name (folder),
1290 transfer_folder_status_cb,
1296 modest_mail_operation_rename_folder (ModestMailOperation *self,
1300 ModestMailOperationPrivate *priv;
1301 ModestTnyFolderRules rules;
1303 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1304 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1305 g_return_if_fail (name);
1307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1309 /* Get account and set it into mail_operation */
1310 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1312 /* Check folder rules */
1313 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1314 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1315 /* Set status failed and set an error */
1316 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1318 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1319 _("FIXME: unable to rename"));
1321 /* Notify about operation end */
1322 modest_mail_operation_notify_end (self);
1324 /* Rename. Camel handles folder subscription/unsubscription */
1325 TnyFolderStore *into;
1327 into = tny_folder_get_folder_store (folder);
1328 tny_folder_copy_async (folder, into, name, TRUE,
1330 transfer_folder_status_cb,
1333 g_object_unref (into);
1338 /* ******************************************************************* */
1339 /* ************************** MSG ACTIONS ************************* */
1340 /* ******************************************************************* */
1342 void modest_mail_operation_get_msg (ModestMailOperation *self,
1344 GetMsgAsyncUserCallback user_callback,
1347 GetMsgAsyncHelper *helper = NULL;
1349 ModestMailOperationPrivate *priv;
1351 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1352 g_return_if_fail (TNY_IS_HEADER (header));
1354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1355 folder = tny_header_get_folder (header);
1357 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1359 /* Get message from folder */
1361 /* Get account and set it into mail_operation */
1362 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1364 helper = g_slice_new0 (GetMsgAsyncHelper);
1365 helper->mail_op = self;
1366 helper->user_callback = user_callback;
1367 helper->pending_ops = 1;
1368 helper->user_data = user_data;
1370 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1372 g_object_unref (G_OBJECT (folder));
1374 /* Set status failed and set an error */
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1376 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1377 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1378 _("Error trying to get a message. No folder found for header"));
1380 /* Notify the queue */
1381 modest_mail_operation_notify_end (self);
1386 get_msg_cb (TnyFolder *folder,
1392 GetMsgAsyncHelper *helper = NULL;
1393 ModestMailOperation *self = NULL;
1394 ModestMailOperationPrivate *priv = NULL;
1396 helper = (GetMsgAsyncHelper *) user_data;
1397 g_return_if_fail (helper != NULL);
1398 self = helper->mail_op;
1399 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1402 helper->pending_ops--;
1404 /* Check errors and cancel */
1406 priv->error = g_error_copy (*error);
1407 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1411 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1412 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1413 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1414 _("Error trying to refresh the contents of %s"),
1415 tny_folder_get_name (folder));
1419 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1421 /* If user defined callback function was defined, call it */
1422 if (helper->user_callback) {
1423 helper->user_callback (self, NULL, msg, helper->user_data);
1428 if (helper->pending_ops == 0) {
1429 g_slice_free (GetMsgAsyncHelper, helper);
1431 /* Notify about operation end */
1432 modest_mail_operation_notify_end (self);
1437 get_msg_status_cb (GObject *obj,
1441 GetMsgAsyncHelper *helper = NULL;
1442 ModestMailOperation *self;
1443 ModestMailOperationPrivate *priv;
1444 ModestMailOperationState *state;
1446 g_return_if_fail (status != NULL);
1447 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1449 helper = (GetMsgAsyncHelper *) user_data;
1450 g_return_if_fail (helper != NULL);
1452 self = helper->mail_op;
1453 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1455 if ((status->position == 1) && (status->of_total == 100))
1461 state = modest_mail_operation_clone_state (self);
1462 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1463 g_slice_free (ModestMailOperationState, state);
1466 /****************************************************/
1468 ModestMailOperation *mail_op;
1470 GetMsgAsyncUserCallback user_callback;
1472 GDestroyNotify notify;
1476 GetMsgAsyncUserCallback user_callback;
1480 ModestMailOperation *mail_op;
1481 } NotifyGetMsgsInfo;
1485 * Used by get_msgs_full_thread to call the user_callback for each
1486 * message that has been read
1489 notify_get_msgs_full (gpointer data)
1491 NotifyGetMsgsInfo *info;
1493 info = (NotifyGetMsgsInfo *) data;
1495 /* Call the user callback */
1496 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1498 g_slice_free (NotifyGetMsgsInfo, info);
1504 * Used by get_msgs_full_thread to free al the thread resources and to
1505 * call the destroy function for the passed user_data
1508 get_msgs_full_destroyer (gpointer data)
1510 GetFullMsgsInfo *info;
1512 info = (GetFullMsgsInfo *) data;
1515 info->notify (info->user_data);
1518 g_object_unref (info->headers);
1519 g_slice_free (GetFullMsgsInfo, info);
1525 get_msgs_full_thread (gpointer thr_user_data)
1527 GetFullMsgsInfo *info;
1528 ModestMailOperationPrivate *priv = NULL;
1529 TnyIterator *iter = NULL;
1531 info = (GetFullMsgsInfo *) thr_user_data;
1532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1534 iter = tny_list_create_iterator (info->headers);
1535 while (!tny_iterator_is_done (iter)) {
1539 header = TNY_HEADER (tny_iterator_get_current (iter));
1540 folder = tny_header_get_folder (header);
1542 /* Get message from folder */
1545 /* The callback will call it per each header */
1546 msg = tny_folder_get_msg (folder, header, &(priv->error));
1549 ModestMailOperationState *state;
1554 /* notify progress */
1555 state = modest_mail_operation_clone_state (info->mail_op);
1556 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1557 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1558 pair, (GDestroyNotify) modest_pair_free);
1560 /* The callback is the responsible for
1561 freeing the message */
1562 if (info->user_callback) {
1563 NotifyGetMsgsInfo *info_notify;
1564 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1565 info_notify->user_callback = info->user_callback;
1566 info_notify->mail_op = info->mail_op;
1567 info_notify->header = g_object_ref (header);
1568 info_notify->msg = g_object_ref (msg);
1569 info_notify->user_data = info->user_data;
1570 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1571 notify_get_msgs_full,
1574 g_object_unref (msg);
1577 /* Set status failed and set an error */
1578 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1579 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1580 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1581 "Error trying to get a message. No folder found for header");
1583 g_object_unref (header);
1584 tny_iterator_next (iter);
1587 /* Set operation status */
1588 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1589 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1591 /* Notify about operation end */
1592 g_idle_add (notify_update_account_queue, info->mail_op);
1594 /* Free thread resources. Will be called after all previous idles */
1595 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1601 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1602 TnyList *header_list,
1603 GetMsgAsyncUserCallback user_callback,
1605 GDestroyNotify notify)
1607 TnyHeader *header = NULL;
1608 TnyFolder *folder = NULL;
1610 ModestMailOperationPrivate *priv = NULL;
1611 GetFullMsgsInfo *info = NULL;
1612 gboolean size_ok = TRUE;
1614 TnyIterator *iter = NULL;
1616 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1618 /* Init mail operation */
1619 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1620 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1622 priv->total = tny_list_get_length(header_list);
1624 /* Get account and set it into mail_operation */
1625 if (tny_list_get_length (header_list) > 1) {
1626 iter = tny_list_create_iterator (header_list);
1627 header = TNY_HEADER (tny_iterator_get_current (iter));
1628 folder = tny_header_get_folder (header);
1629 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1630 g_object_unref (header);
1631 g_object_unref (folder);
1634 /* Get msg size limit */
1635 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1636 MODEST_CONF_MSG_SIZE_LIMIT,
1639 g_clear_error (&(priv->error));
1640 max_size = G_MAXINT;
1642 max_size = max_size * KB;
1645 /* Check message size limits. If there is only one message
1646 always retrieve it */
1648 while (!tny_iterator_is_done (iter) && size_ok) {
1649 header = TNY_HEADER (tny_iterator_get_current (iter));
1650 if (tny_header_get_message_size (header) >= max_size)
1652 g_object_unref (header);
1653 tny_iterator_next (iter);
1655 g_object_unref (iter);
1659 /* Create the info */
1660 info = g_slice_new0 (GetFullMsgsInfo);
1661 info->mail_op = self;
1662 info->user_callback = user_callback;
1663 info->user_data = user_data;
1664 info->headers = g_object_ref (header_list);
1665 info->notify = notify;
1667 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1669 /* Set status failed and set an error */
1670 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1671 /* FIXME: the error msg is different for pop */
1672 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1673 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1674 _("emev_ni_ui_imap_msg_size_exceed_error"));
1675 /* Remove from queue and free resources */
1676 modest_mail_operation_notify_end (self);
1684 modest_mail_operation_remove_msg (ModestMailOperation *self,
1686 gboolean remove_to_trash)
1689 ModestMailOperationPrivate *priv;
1691 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1692 g_return_if_fail (TNY_IS_HEADER (header));
1694 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1695 folder = tny_header_get_folder (header);
1697 /* Get account and set it into mail_operation */
1698 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1702 /* Delete or move to trash */
1703 if (remove_to_trash) {
1704 TnyFolder *trash_folder;
1705 TnyStoreAccount *store_account;
1707 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1708 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1709 TNY_FOLDER_TYPE_TRASH);
1714 headers = tny_simple_list_new ();
1715 tny_list_append (headers, G_OBJECT (header));
1716 g_object_unref (header);
1719 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1720 g_object_unref (headers);
1721 /* g_object_unref (trash_folder); */
1723 ModestMailOperationPrivate *priv;
1725 /* Set status failed and set an error */
1726 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1727 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1728 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1729 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1730 _("Error trying to delete a message. Trash folder not found"));
1733 g_object_unref (G_OBJECT (store_account));
1735 tny_folder_remove_msg (folder, header, &(priv->error));
1737 tny_folder_sync(folder, TRUE, &(priv->error));
1742 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1747 g_object_unref (G_OBJECT (folder));
1749 /* Notify about operation end */
1750 modest_mail_operation_notify_end (self);
1754 transfer_msgs_status_cb (GObject *obj,
1758 XFerMsgAsyncHelper *helper = NULL;
1759 ModestMailOperation *self;
1760 ModestMailOperationPrivate *priv;
1761 ModestMailOperationState *state;
1764 g_return_if_fail (status != NULL);
1765 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1767 helper = (XFerMsgAsyncHelper *) user_data;
1768 g_return_if_fail (helper != NULL);
1770 self = helper->mail_op;
1771 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1773 if ((status->position == 1) && (status->of_total == 100))
1776 priv->done = status->position;
1777 priv->total = status->of_total;
1779 state = modest_mail_operation_clone_state (self);
1780 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1781 g_slice_free (ModestMailOperationState, state);
1786 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1788 XFerMsgAsyncHelper *helper;
1789 ModestMailOperation *self;
1790 ModestMailOperationPrivate *priv;
1792 helper = (XFerMsgAsyncHelper *) user_data;
1793 self = helper->mail_op;
1795 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1798 priv->error = g_error_copy (*err);
1800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1801 } else if (cancelled) {
1802 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1803 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1804 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1805 _("Error trying to refresh the contents of %s"),
1806 tny_folder_get_name (folder));
1809 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1812 /* If user defined callback function was defined, call it */
1813 if (helper->user_callback) {
1814 helper->user_callback (priv->source, helper->user_data);
1818 g_object_unref (helper->headers);
1819 g_object_unref (helper->dest_folder);
1820 g_object_unref (helper->mail_op);
1821 g_slice_free (XFerMsgAsyncHelper, helper);
1822 g_object_unref (folder);
1824 /* Notify about operation end */
1825 modest_mail_operation_notify_end (self);
1829 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1832 gboolean delete_original,
1833 XferMsgsAsynUserCallback user_callback,
1836 ModestMailOperationPrivate *priv;
1838 TnyFolder *src_folder;
1839 XFerMsgAsyncHelper *helper;
1841 ModestTnyFolderRules rules;
1843 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1844 g_return_if_fail (TNY_IS_LIST (headers));
1845 g_return_if_fail (TNY_IS_FOLDER (folder));
1847 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1850 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1852 /* Apply folder rules */
1853 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1855 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1856 /* Set status failed and set an error */
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1858 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1859 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1860 _("FIXME: folder does not accept msgs"));
1861 /* Notify the queue */
1862 modest_mail_operation_notify_end (self);
1866 /* Create the helper */
1867 helper = g_slice_new0 (XFerMsgAsyncHelper);
1868 helper->mail_op = g_object_ref(self);
1869 helper->dest_folder = g_object_ref(folder);
1870 helper->headers = g_object_ref(headers);
1871 helper->user_callback = user_callback;
1872 helper->user_data = user_data;
1874 /* Get source folder */
1875 iter = tny_list_create_iterator (headers);
1876 header = TNY_HEADER (tny_iterator_get_current (iter));
1877 src_folder = tny_header_get_folder (header);
1878 g_object_unref (header);
1879 g_object_unref (iter);
1881 /* Get account and set it into mail_operation */
1882 priv->account = tny_folder_get_account (src_folder);
1884 /* Transfer messages */
1885 tny_folder_transfer_msgs_async (src_folder,
1890 transfer_msgs_status_cb,
1896 on_refresh_folder (TnyFolder *folder,
1901 ModestMailOperation *self;
1902 ModestMailOperationPrivate *priv;
1904 self = MODEST_MAIL_OPERATION (user_data);
1905 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1908 priv->error = g_error_copy (*error);
1909 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1914 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1915 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1916 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1917 _("Error trying to refresh the contents of %s"),
1918 tny_folder_get_name (folder));
1922 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1926 g_object_unref (folder);
1928 /* Notify about operation end */
1929 modest_mail_operation_notify_end (self);
1933 on_refresh_folder_status_update (GObject *obj,
1937 ModestMailOperation *self;
1938 ModestMailOperationPrivate *priv;
1939 ModestMailOperationState *state;
1941 g_return_if_fail (status != NULL);
1942 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1944 self = MODEST_MAIL_OPERATION (user_data);
1945 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1947 priv->done = status->position;
1948 priv->total = status->of_total;
1950 state = modest_mail_operation_clone_state (self);
1951 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1952 g_slice_free (ModestMailOperationState, state);
1956 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1959 ModestMailOperationPrivate *priv;
1961 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1963 /* Pick a reference */
1964 g_object_ref (folder);
1966 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1968 /* Get account and set it into mail_operation */
1969 priv->account = tny_folder_get_account (folder);
1971 /* Refresh the folder. TODO: tinymail could issue a status
1972 updates before the callback call then this could happen. We
1973 must review the design */
1974 tny_folder_refresh_async (folder,
1976 on_refresh_folder_status_update,
1982 * It's used by the mail operation queue to notify the observers
1983 * attached to that signal that the operation finished. We need to use
1984 * that because tinymail does not give us the progress of a given
1985 * operation when it finishes (it directly calls the operation
1989 modest_mail_operation_notify_end (ModestMailOperation *self)
1991 ModestMailOperationState *state;
1993 /* Notify the observers about the mail opertation end */
1994 state = modest_mail_operation_clone_state (self);
1995 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1996 g_slice_free (ModestMailOperationState, state);
1998 /* Notify the queue */
1999 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);