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 static gboolean did_a_cancel = FALSE;
76 enum _ModestMailOperationSignals
78 PROGRESS_CHANGED_SIGNAL,
83 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
84 struct _ModestMailOperationPrivate {
90 ErrorCheckingUserCallback error_checking;
91 gpointer error_checking_user_data;
92 ModestMailOperationStatus status;
93 ModestMailOperationTypeOperation op_type;
96 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
97 MODEST_TYPE_MAIL_OPERATION, \
98 ModestMailOperationPrivate))
100 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
101 priv->status = new_status;\
104 typedef struct _GetMsgAsyncHelper {
105 ModestMailOperation *mail_op;
106 GetMsgAsyncUserCallback user_callback;
111 typedef struct _XFerMsgAsyncHelper
113 ModestMailOperation *mail_op;
115 TnyFolder *dest_folder;
116 XferMsgsAsynUserCallback user_callback;
118 } XFerMsgAsyncHelper;
121 static GObjectClass *parent_class = NULL;
123 static guint signals[NUM_SIGNALS] = {0};
126 modest_mail_operation_get_type (void)
128 static GType my_type = 0;
130 static const GTypeInfo my_info = {
131 sizeof(ModestMailOperationClass),
132 NULL, /* base init */
133 NULL, /* base finalize */
134 (GClassInitFunc) modest_mail_operation_class_init,
135 NULL, /* class finalize */
136 NULL, /* class data */
137 sizeof(ModestMailOperation),
139 (GInstanceInitFunc) modest_mail_operation_init,
142 my_type = g_type_register_static (G_TYPE_OBJECT,
143 "ModestMailOperation",
150 modest_mail_operation_class_init (ModestMailOperationClass *klass)
152 GObjectClass *gobject_class;
153 gobject_class = (GObjectClass*) klass;
155 parent_class = g_type_class_peek_parent (klass);
156 gobject_class->finalize = modest_mail_operation_finalize;
158 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
161 * ModestMailOperation::progress-changed
162 * @self: the #MailOperation that emits the signal
163 * @user_data: user data set when the signal handler was connected
165 * Emitted when the progress of a mail operation changes
167 signals[PROGRESS_CHANGED_SIGNAL] =
168 g_signal_new ("progress-changed",
169 G_TYPE_FROM_CLASS (gobject_class),
171 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
173 g_cclosure_marshal_VOID__POINTER,
174 G_TYPE_NONE, 1, G_TYPE_POINTER);
178 modest_mail_operation_init (ModestMailOperation *obj)
180 ModestMailOperationPrivate *priv;
182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
184 priv->account = NULL;
185 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
186 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
191 priv->error_checking = NULL;
192 priv->error_checking_user_data = NULL;
196 modest_mail_operation_finalize (GObject *obj)
198 ModestMailOperationPrivate *priv;
200 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
203 g_error_free (priv->error);
207 g_object_unref (priv->source);
211 g_object_unref (priv->account);
212 priv->account = NULL;
216 G_OBJECT_CLASS(parent_class)->finalize (obj);
220 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
223 ModestMailOperation *obj;
224 ModestMailOperationPrivate *priv;
226 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
227 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
229 priv->op_type = op_type;
231 priv->source = g_object_ref(source);
237 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
239 ErrorCheckingUserCallback error_handler,
242 ModestMailOperation *obj;
243 ModestMailOperationPrivate *priv;
245 obj = modest_mail_operation_new (op_type, source);
246 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
248 g_return_val_if_fail (error_handler != NULL, obj);
249 priv->error_checking = error_handler;
255 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
257 ModestMailOperationPrivate *priv;
259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
260 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
262 if (priv->error_checking != NULL)
263 priv->error_checking (self, priv->error_checking_user_data);
267 ModestMailOperationTypeOperation
268 modest_mail_operation_get_type_operation (ModestMailOperation *self)
270 ModestMailOperationPrivate *priv;
272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
274 return priv->op_type;
278 modest_mail_operation_is_mine (ModestMailOperation *self,
281 ModestMailOperationPrivate *priv;
283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
284 if (priv->source == NULL) return FALSE;
286 return priv->source == me;
290 modest_mail_operation_get_source (ModestMailOperation *self)
292 ModestMailOperationPrivate *priv;
294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
296 return g_object_ref (priv->source);
299 ModestMailOperationStatus
300 modest_mail_operation_get_status (ModestMailOperation *self)
302 ModestMailOperationPrivate *priv;
304 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
305 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
306 MODEST_MAIL_OPERATION_STATUS_INVALID);
308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
313 modest_mail_operation_get_error (ModestMailOperation *self)
315 ModestMailOperationPrivate *priv;
317 g_return_val_if_fail (self, NULL);
318 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
320 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
325 modest_mail_operation_cancel (ModestMailOperation *self)
327 ModestMailOperationPrivate *priv;
329 if (!MODEST_IS_MAIL_OPERATION (self)) {
330 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
334 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
336 /* cancel current operation in account */
337 tny_account_cancel (priv->account);
342 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
344 /* Notify about operation end */
345 modest_mail_operation_notify_end (self);
351 modest_mail_operation_get_task_done (ModestMailOperation *self)
353 ModestMailOperationPrivate *priv;
355 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
362 modest_mail_operation_get_task_total (ModestMailOperation *self)
364 ModestMailOperationPrivate *priv;
366 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
368 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
373 modest_mail_operation_is_finished (ModestMailOperation *self)
375 ModestMailOperationPrivate *priv;
376 gboolean retval = FALSE;
378 if (!MODEST_IS_MAIL_OPERATION (self)) {
379 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
383 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
385 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
386 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
387 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
388 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
398 modest_mail_operation_get_id (ModestMailOperation *self)
400 ModestMailOperationPrivate *priv;
402 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
404 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
409 modest_mail_operation_set_id (ModestMailOperation *self,
412 ModestMailOperationPrivate *priv;
414 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
421 * Creates an image of the current state of a mail operation, the
422 * caller must free it
424 static ModestMailOperationState *
425 modest_mail_operation_clone_state (ModestMailOperation *self)
427 ModestMailOperationState *state;
428 ModestMailOperationPrivate *priv;
430 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
432 state = g_slice_new (ModestMailOperationState);
434 state->status = priv->status;
435 state->op_type = priv->op_type;
436 state->done = priv->done;
437 state->total = priv->total;
438 state->finished = modest_mail_operation_is_finished (self);
443 /* ******************************************************************* */
444 /* ************************** SEND ACTIONS ************************* */
445 /* ******************************************************************* */
448 modest_mail_operation_send_mail (ModestMailOperation *self,
449 TnyTransportAccount *transport_account,
452 TnySendQueue *send_queue = NULL;
453 ModestMailOperationPrivate *priv;
455 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
456 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
457 g_return_if_fail (TNY_IS_MSG (msg));
459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
461 /* Get account and set it into mail_operation */
462 priv->account = g_object_ref (transport_account);
464 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
465 if (!TNY_IS_SEND_QUEUE(send_queue)) {
466 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
467 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
468 "modest: could not find send queue for account\n");
470 tny_send_queue_add (send_queue, msg, &(priv->error));
473 /* Notify about operation end */
474 modest_mail_operation_notify_end (self);
478 modest_mail_operation_send_new_mail (ModestMailOperation *self,
479 TnyTransportAccount *transport_account,
481 const gchar *from, const gchar *to,
482 const gchar *cc, const gchar *bcc,
483 const gchar *subject, const gchar *plain_body,
484 const gchar *html_body,
485 const GList *attachments_list,
486 TnyHeaderFlags priority_flags)
488 TnyMsg *new_msg = NULL;
489 TnyFolder *folder = NULL;
490 ModestMailOperationPrivate *priv = NULL;
492 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
493 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
495 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
497 /* Get account and set it into mail_operation */
498 priv->account = g_object_ref (transport_account);
500 /* Check parametters */
502 /* Set status failed and set an error */
503 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
504 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
505 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
506 _("Error trying to send a mail. You need to set at least one recipient"));
510 if (html_body == NULL) {
511 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
513 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
516 g_printerr ("modest: failed to create a new msg\n");
520 /* TODO: add priority handling. It's received in the priority_flags operator, and
521 it should have effect in the sending operation */
523 /* Call mail operation */
524 modest_mail_operation_send_mail (self, transport_account, new_msg);
526 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
528 if (draft_msg != NULL) {
529 TnyHeader *header = tny_msg_get_header (draft_msg);
530 tny_folder_remove_msg (folder, header, NULL);
531 g_object_unref (header);
536 g_object_unref (G_OBJECT (new_msg));
540 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
541 TnyTransportAccount *transport_account,
543 const gchar *from, const gchar *to,
544 const gchar *cc, const gchar *bcc,
545 const gchar *subject, const gchar *plain_body,
546 const gchar *html_body,
547 const GList *attachments_list,
548 TnyHeaderFlags priority_flags)
551 TnyFolder *folder = NULL;
552 ModestMailOperationPrivate *priv = NULL;
554 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
555 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
557 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
559 /* Get account and set it into mail_operation */
560 priv->account = g_object_ref (transport_account);
562 if (html_body == NULL) {
563 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
565 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
568 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
569 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
570 "modest: failed to create a new msg\n");
574 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
576 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
577 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
578 "modest: failed to create a new msg\n");
582 if (draft_msg != NULL) {
583 TnyHeader *header = tny_msg_get_header (draft_msg);
584 tny_folder_remove_msg (folder, header, NULL);
585 g_object_unref (header);
588 tny_folder_add_msg (folder, msg, &(priv->error));
594 g_object_unref (G_OBJECT(msg));
596 g_object_unref (G_OBJECT(folder));
598 modest_mail_operation_notify_end (self);
603 ModestMailOperation *mail_op;
604 TnyStoreAccount *account;
605 TnyTransportAccount *transport_account;
608 gchar *retrieve_type;
611 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
612 /* We use this folder observer to track the headers that have been
613 * added to a folder */
616 TnyList *new_headers;
617 } InternalFolderObserver;
621 } InternalFolderObserverClass;
623 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
625 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
626 internal_folder_observer,
628 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
632 foreach_add_item (gpointer header, gpointer user_data)
634 /* printf("DEBUG: %s: header subject=%s\n",
635 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
637 tny_list_prepend (TNY_LIST (user_data),
638 g_object_ref (G_OBJECT (header)));
641 /* This is the method that looks for new messages in a folder */
643 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
645 InternalFolderObserver *derived = (InternalFolderObserver *)self;
647 TnyFolderChangeChanged changed;
649 changed = tny_folder_change_get_changed (change);
651 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
654 /* Get added headers */
655 list = tny_simple_list_new ();
656 tny_folder_change_get_added_headers (change, list);
658 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
659 * __FUNCTION__, tny_list_get_length(list));
662 /* Add them to the folder observer */
663 tny_list_foreach (list, foreach_add_item,
664 derived->new_headers);
666 g_object_unref (G_OBJECT (list));
671 internal_folder_observer_init (InternalFolderObserver *self)
673 self->new_headers = tny_simple_list_new ();
676 internal_folder_observer_finalize (GObject *object)
678 InternalFolderObserver *self;
680 self = (InternalFolderObserver *) object;
681 g_object_unref (self->new_headers);
683 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
686 tny_folder_observer_init (TnyFolderObserverIface *iface)
688 iface->update_func = internal_folder_observer_update;
691 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
693 GObjectClass *object_class;
695 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
696 object_class = (GObjectClass*) klass;
697 object_class->finalize = internal_folder_observer_finalize;
703 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
706 TnyList *folders = tny_simple_list_new ();
708 tny_folder_store_get_folders (store, folders, query, NULL);
709 iter = tny_list_create_iterator (folders);
711 while (!tny_iterator_is_done (iter)) {
713 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
715 tny_list_prepend (all_folders, G_OBJECT (folder));
716 recurse_folders (folder, query, all_folders);
717 g_object_unref (G_OBJECT (folder));
719 tny_iterator_next (iter);
721 g_object_unref (G_OBJECT (iter));
722 g_object_unref (G_OBJECT (folders));
726 * Issues the "progress-changed" signal. The timer won't be removed,
727 * so you must call g_source_remove to stop the signal emission
730 idle_notify_progress (gpointer data)
732 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
733 ModestMailOperationState *state;
735 state = modest_mail_operation_clone_state (mail_op);
736 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
737 g_slice_free (ModestMailOperationState, state);
743 * Issues the "progress-changed" signal and removes the timer. It uses
744 * a lock to ensure that the progress information of the mail
745 * operation is not modified while there are notifications pending
748 idle_notify_progress_once (gpointer data)
752 pair = (ModestPair *) data;
754 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
756 /* Free the state and the reference to the mail operation */
757 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
758 g_object_unref (pair->first);
764 * Used by update_account_thread to notify the queue from the main
765 * loop. We call it inside an idle call to achieve that
768 notify_update_account_queue (gpointer data)
770 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
772 modest_mail_operation_notify_end (mail_op);
773 g_object_unref (mail_op);
779 compare_headers_by_date (gconstpointer a,
782 TnyHeader **header1, **header2;
785 header1 = (TnyHeader **) a;
786 header2 = (TnyHeader **) b;
788 sent1 = tny_header_get_date_sent (*header1);
789 sent2 = tny_header_get_date_sent (*header2);
791 /* We want the most recent ones (greater time_t) at the
800 update_account_thread (gpointer thr_user_data)
802 UpdateAccountInfo *info;
803 TnyList *all_folders = NULL;
804 GPtrArray *new_headers;
805 TnyIterator *iter = NULL;
806 TnyFolderStoreQuery *query = NULL;
807 ModestMailOperationPrivate *priv;
808 ModestTnySendQueue *send_queue;
810 info = (UpdateAccountInfo *) thr_user_data;
811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
813 /* Get account and set it into mail_operation */
814 priv->account = g_object_ref (info->account);
816 /* Get all the folders. We can do it synchronously because
817 we're already running in a different thread than the UI */
818 all_folders = tny_simple_list_new ();
819 query = tny_folder_store_query_new ();
820 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
821 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
830 iter = tny_list_create_iterator (all_folders);
831 while (!tny_iterator_is_done (iter)) {
832 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
834 recurse_folders (folder, query, all_folders);
835 tny_iterator_next (iter);
837 g_object_unref (G_OBJECT (iter));
839 /* Update status and notify. We need to call the notification
840 with a source function in order to call it from the main
841 loop. We need that in order not to get into trouble with
842 Gtk+. We use a timeout in order to provide more status
843 information, because the sync tinymail call does not
844 provide it for the moment */
845 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
847 /* Refresh folders */
848 new_headers = g_ptr_array_new ();
849 iter = tny_list_create_iterator (all_folders);
851 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
853 InternalFolderObserver *observer;
854 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
856 /* Refresh the folder */
857 /* Our observer receives notification of new emails during folder refreshes,
858 * so we can use observer->new_headers.
859 * TODO: This does not seem to be providing accurate numbers.
860 * Possibly the observer is notified asynchronously.
862 observer = g_object_new (internal_folder_observer_get_type (), NULL);
863 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
865 /* This gets the status information (headers) from the server.
866 * We use the blocking version, because we are already in a separate
869 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
871 /* If the retrieve type is headers only do nothing more */
872 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
873 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
876 iter = tny_list_create_iterator (observer->new_headers);
877 while (!tny_iterator_is_done (iter)) {
878 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
879 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
880 * __FUNCTION__, tny_account_get_id (priv->account),
881 * tny_header_get_subject (header));
884 /* Apply per-message size limits */
885 if (tny_header_get_message_size (header) < info->max_size)
886 g_ptr_array_add (new_headers, g_object_ref (header));
888 g_object_unref (header);
889 tny_iterator_next (iter);
891 g_object_unref (iter);
894 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
895 g_object_unref (observer);
899 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
901 g_object_unref (G_OBJECT (folder));
902 tny_iterator_next (iter);
905 did_a_cancel = FALSE;
907 g_object_unref (G_OBJECT (iter));
908 g_source_remove (timeout);
910 if (new_headers->len > 0) {
914 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
916 /* Apply message count limit */
917 /* If the number of messages exceeds the maximum, ask the
918 * user to download them all,
919 * as per the UI spec "Retrieval Limits" section in 4.4:
921 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
922 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
923 if (new_headers->len > info->retrieve_limit) {
924 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
925 * with 'Get all' and 'Newest only' buttons. */
926 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
927 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
928 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
929 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
930 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
935 priv->total = MIN (new_headers->len, info->retrieve_limit);
936 while (msg_num < priv->total) {
938 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
939 TnyFolder *folder = tny_header_get_folder (header);
940 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
941 ModestMailOperationState *state;
945 /* We can not just use the mail operation because the
946 values of done and total could change before the
948 state = modest_mail_operation_clone_state (info->mail_op);
949 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
950 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
951 pair, (GDestroyNotify) modest_pair_free);
953 g_object_unref (msg);
954 g_object_unref (folder);
958 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
959 g_ptr_array_free (new_headers, FALSE);
963 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
966 if (priv->account != NULL)
967 g_object_unref (priv->account);
968 priv->account = g_object_ref (info->transport_account);
970 send_queue = modest_runtime_get_send_queue (info->transport_account);
972 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
973 modest_tny_send_queue_try_to_send (send_queue);
974 g_source_remove (timeout);
976 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
977 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
978 "cannot create a send queue for %s\n",
979 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
983 /* Check if the operation was a success */
985 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
987 /* Update the last updated key */
988 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
989 tny_account_get_id (TNY_ACCOUNT (info->account)),
990 MODEST_ACCOUNT_LAST_UPDATED,
996 /* Notify about operation end. Note that the info could be
997 freed before this idle happens, but the mail operation will
999 g_idle_add (notify_update_account_queue, info->mail_op);
1002 g_object_unref (query);
1003 g_object_unref (all_folders);
1004 g_object_unref (info->account);
1005 g_object_unref (info->transport_account);
1006 g_free (info->retrieve_type);
1007 g_slice_free (UpdateAccountInfo, info);
1013 modest_mail_operation_update_account (ModestMailOperation *self,
1014 const gchar *account_name)
1017 UpdateAccountInfo *info;
1018 ModestMailOperationPrivate *priv;
1019 ModestAccountMgr *mgr;
1020 TnyStoreAccount *modest_account;
1021 TnyTransportAccount *transport_account;
1023 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1024 g_return_val_if_fail (account_name, FALSE);
1026 /* Make sure that we have a connection, and request one
1028 * TODO: Is there some way to trigger this for every attempt to
1029 * use the network? */
1030 if (!modest_platform_connect_and_wait(NULL))
1033 /* Init mail operation. Set total and done to 0, and do not
1034 update them, this way the progress objects will know that
1035 we have no clue about the number of the objects */
1036 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1039 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1041 /* Get the Modest account */
1042 modest_account = (TnyStoreAccount *)
1043 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
1045 TNY_ACCOUNT_TYPE_STORE);
1047 if (!modest_account) {
1048 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1049 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1050 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1051 "cannot get tny store account for %s\n", account_name);
1052 modest_mail_operation_notify_end (self);
1056 /* Get the transport account, we can not do it in the thread
1057 due to some problems with dbus */
1058 transport_account = (TnyTransportAccount *)
1059 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1061 if (!transport_account) {
1062 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1063 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1064 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1065 "cannot get tny transport account for %s\n", account_name);
1066 modest_mail_operation_notify_end (self);
1070 /* Create the helper object */
1071 info = g_slice_new (UpdateAccountInfo);
1072 info->mail_op = self;
1073 info->account = modest_account;
1074 info->transport_account = transport_account;
1076 /* Get the message size limit */
1077 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1078 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1079 if (info->max_size == 0)
1080 info->max_size = G_MAXINT;
1082 info->max_size = info->max_size * KB;
1084 /* Get per-account retrieval type */
1085 mgr = modest_runtime_get_account_mgr ();
1086 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1087 MODEST_ACCOUNT_RETRIEVE, FALSE);
1089 /* Get per-account message amount retrieval limit */
1090 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1091 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1092 if (info->retrieve_limit == 0)
1093 info->retrieve_limit = G_MAXINT;
1095 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1097 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1102 /* ******************************************************************* */
1103 /* ************************** STORE ACTIONS ************************* */
1104 /* ******************************************************************* */
1108 modest_mail_operation_create_folder (ModestMailOperation *self,
1109 TnyFolderStore *parent,
1112 ModestMailOperationPrivate *priv;
1113 TnyFolder *new_folder = NULL;
1115 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1116 g_return_val_if_fail (name, NULL);
1118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1121 if (TNY_IS_FOLDER (parent)) {
1122 /* Check folder rules */
1123 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1124 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1125 /* Set status failed and set an error */
1126 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1127 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1128 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1129 _("mail_in_ui_folder_create_error"));
1134 /* Create the folder */
1135 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1136 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1138 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1141 /* Notify about operation end */
1142 modest_mail_operation_notify_end (self);
1148 modest_mail_operation_remove_folder (ModestMailOperation *self,
1150 gboolean remove_to_trash)
1152 TnyAccount *account;
1153 ModestMailOperationPrivate *priv;
1154 ModestTnyFolderRules rules;
1156 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1157 g_return_if_fail (TNY_IS_FOLDER (folder));
1159 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1161 /* Check folder rules */
1162 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1163 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1164 /* Set status failed and set an error */
1165 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1166 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1167 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1168 _("mail_in_ui_folder_delete_error"));
1172 /* Get the account */
1173 account = modest_tny_folder_get_account (folder);
1174 priv->account = g_object_ref(account);
1176 /* Delete folder or move to trash */
1177 if (remove_to_trash) {
1178 TnyFolder *trash_folder = NULL;
1179 trash_folder = modest_tny_account_get_special_folder (account,
1180 TNY_FOLDER_TYPE_TRASH);
1181 /* TODO: error_handling */
1182 modest_mail_operation_xfer_folder (self, folder,
1183 TNY_FOLDER_STORE (trash_folder), TRUE);
1185 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1187 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1188 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1191 g_object_unref (G_OBJECT (parent));
1193 g_object_unref (G_OBJECT (account));
1196 /* Notify about operation end */
1197 modest_mail_operation_notify_end (self);
1201 transfer_folder_status_cb (GObject *obj,
1205 ModestMailOperation *self;
1206 ModestMailOperationPrivate *priv;
1207 ModestMailOperationState *state;
1209 g_return_if_fail (status != NULL);
1210 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1212 self = MODEST_MAIL_OPERATION (user_data);
1213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1215 if ((status->position == 1) && (status->of_total == 100))
1218 priv->done = status->position;
1219 priv->total = status->of_total;
1221 state = modest_mail_operation_clone_state (self);
1222 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1223 g_slice_free (ModestMailOperationState, state);
1228 transfer_folder_cb (TnyFolder *folder,
1229 TnyFolderStore *into,
1231 TnyFolder *new_folder, GError **err,
1234 ModestMailOperation *self = NULL;
1235 ModestMailOperationPrivate *priv = NULL;
1237 self = MODEST_MAIL_OPERATION (user_data);
1239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1242 priv->error = g_error_copy (*err);
1244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1245 } else if (cancelled) {
1246 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1247 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1248 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1249 _("Transference of %s was cancelled."),
1250 tny_folder_get_name (folder));
1253 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1257 g_object_unref (folder);
1258 g_object_unref (into);
1259 if (new_folder != NULL)
1260 g_object_unref (new_folder);
1262 /* Notify about operation end */
1263 modest_mail_operation_notify_end (self);
1267 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1269 TnyFolderStore *parent,
1270 gboolean delete_original)
1272 ModestMailOperationPrivate *priv = NULL;
1273 ModestTnyFolderRules parent_rules, rules;
1275 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1276 g_return_if_fail (TNY_IS_FOLDER (folder));
1277 g_return_if_fail (TNY_IS_FOLDER (parent));
1279 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1281 /* Get account and set it into mail_operation */
1282 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1283 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1285 /* Get folder rules */
1286 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1287 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1289 if (!TNY_IS_FOLDER_STORE (parent)) {
1293 /* The moveable restriction is applied also to copy operation */
1294 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1295 /* Set status failed and set an error */
1296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1297 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1298 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1299 _("mail_in_ui_folder_move_target_error"));
1301 /* Notify the queue */
1302 modest_mail_operation_notify_end (self);
1303 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1304 /* Set status failed and set an error */
1305 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1306 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1307 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1308 _("FIXME: parent folder does not accept new folders"));
1310 /* Notify the queue */
1311 modest_mail_operation_notify_end (self);
1313 /* Pick references for async calls */
1314 g_object_ref (folder);
1315 g_object_ref (parent);
1317 /* Move/Copy folder */
1318 tny_folder_copy_async (folder,
1320 tny_folder_get_name (folder),
1323 transfer_folder_status_cb,
1329 modest_mail_operation_rename_folder (ModestMailOperation *self,
1333 ModestMailOperationPrivate *priv;
1334 ModestTnyFolderRules rules;
1336 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1337 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1338 g_return_if_fail (name);
1340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1342 /* Get account and set it into mail_operation */
1343 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1345 /* Check folder rules */
1346 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1347 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1348 /* Set status failed and set an error */
1349 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1350 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1351 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1352 _("FIXME: unable to rename"));
1354 /* Notify about operation end */
1355 modest_mail_operation_notify_end (self);
1357 /* Rename. Camel handles folder subscription/unsubscription */
1358 TnyFolderStore *into;
1360 into = tny_folder_get_folder_store (folder);
1361 tny_folder_copy_async (folder, into, name, TRUE,
1363 transfer_folder_status_cb,
1366 g_object_unref (into);
1371 /* ******************************************************************* */
1372 /* ************************** MSG ACTIONS ************************* */
1373 /* ******************************************************************* */
1375 void modest_mail_operation_get_msg (ModestMailOperation *self,
1377 GetMsgAsyncUserCallback user_callback,
1380 GetMsgAsyncHelper *helper = NULL;
1382 ModestMailOperationPrivate *priv;
1384 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1385 g_return_if_fail (TNY_IS_HEADER (header));
1387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1388 folder = tny_header_get_folder (header);
1390 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1392 /* Get message from folder */
1394 /* Get account and set it into mail_operation */
1395 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1397 helper = g_slice_new0 (GetMsgAsyncHelper);
1398 helper->mail_op = self;
1399 helper->user_callback = user_callback;
1400 helper->pending_ops = 1;
1401 helper->user_data = user_data;
1403 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1405 g_object_unref (G_OBJECT (folder));
1407 /* Set status failed and set an error */
1408 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1409 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1410 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1411 _("Error trying to get a message. No folder found for header"));
1413 /* Notify the queue */
1414 modest_mail_operation_notify_end (self);
1419 get_msg_cb (TnyFolder *folder,
1425 GetMsgAsyncHelper *helper = NULL;
1426 ModestMailOperation *self = NULL;
1427 ModestMailOperationPrivate *priv = NULL;
1429 helper = (GetMsgAsyncHelper *) user_data;
1430 g_return_if_fail (helper != NULL);
1431 self = helper->mail_op;
1432 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1435 helper->pending_ops--;
1437 /* Check errors and cancel */
1439 priv->error = g_error_copy (*error);
1440 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1444 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1445 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1446 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1447 _("Error trying to refresh the contents of %s"),
1448 tny_folder_get_name (folder));
1452 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1454 /* If user defined callback function was defined, call it */
1455 if (helper->user_callback) {
1456 helper->user_callback (self, NULL, msg, helper->user_data);
1461 if (helper->pending_ops == 0) {
1462 g_slice_free (GetMsgAsyncHelper, helper);
1464 /* Notify about operation end */
1465 modest_mail_operation_notify_end (self);
1470 get_msg_status_cb (GObject *obj,
1474 GetMsgAsyncHelper *helper = NULL;
1475 ModestMailOperation *self;
1476 ModestMailOperationPrivate *priv;
1477 ModestMailOperationState *state;
1479 g_return_if_fail (status != NULL);
1480 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1482 helper = (GetMsgAsyncHelper *) user_data;
1483 g_return_if_fail (helper != NULL);
1485 self = helper->mail_op;
1486 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1488 if ((status->position == 1) && (status->of_total == 100))
1494 state = modest_mail_operation_clone_state (self);
1495 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1496 g_slice_free (ModestMailOperationState, state);
1499 /****************************************************/
1501 ModestMailOperation *mail_op;
1503 GetMsgAsyncUserCallback user_callback;
1505 GDestroyNotify notify;
1509 GetMsgAsyncUserCallback user_callback;
1513 ModestMailOperation *mail_op;
1514 } NotifyGetMsgsInfo;
1518 * Used by get_msgs_full_thread to call the user_callback for each
1519 * message that has been read
1522 notify_get_msgs_full (gpointer data)
1524 NotifyGetMsgsInfo *info;
1526 info = (NotifyGetMsgsInfo *) data;
1528 /* Call the user callback */
1529 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1531 g_slice_free (NotifyGetMsgsInfo, info);
1537 * Used by get_msgs_full_thread to free al the thread resources and to
1538 * call the destroy function for the passed user_data
1541 get_msgs_full_destroyer (gpointer data)
1543 GetFullMsgsInfo *info;
1545 info = (GetFullMsgsInfo *) data;
1548 info->notify (info->user_data);
1551 g_object_unref (info->headers);
1552 g_slice_free (GetFullMsgsInfo, info);
1558 get_msgs_full_thread (gpointer thr_user_data)
1560 GetFullMsgsInfo *info;
1561 ModestMailOperationPrivate *priv = NULL;
1562 TnyIterator *iter = NULL;
1564 info = (GetFullMsgsInfo *) thr_user_data;
1565 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1567 iter = tny_list_create_iterator (info->headers);
1568 while (!tny_iterator_is_done (iter)) {
1572 header = TNY_HEADER (tny_iterator_get_current (iter));
1573 folder = tny_header_get_folder (header);
1575 /* Get message from folder */
1578 /* The callback will call it per each header */
1579 msg = tny_folder_get_msg (folder, header, &(priv->error));
1582 ModestMailOperationState *state;
1587 /* notify progress */
1588 state = modest_mail_operation_clone_state (info->mail_op);
1589 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1590 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1591 pair, (GDestroyNotify) modest_pair_free);
1593 /* The callback is the responsible for
1594 freeing the message */
1595 if (info->user_callback) {
1596 NotifyGetMsgsInfo *info_notify;
1597 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1598 info_notify->user_callback = info->user_callback;
1599 info_notify->mail_op = info->mail_op;
1600 info_notify->header = g_object_ref (header);
1601 info_notify->msg = g_object_ref (msg);
1602 info_notify->user_data = info->user_data;
1603 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1604 notify_get_msgs_full,
1607 g_object_unref (msg);
1610 /* Set status failed and set an error */
1611 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1612 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1613 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1614 "Error trying to get a message. No folder found for header");
1616 g_object_unref (header);
1617 tny_iterator_next (iter);
1620 /* Set operation status */
1621 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1622 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1624 /* Notify about operation end */
1625 g_idle_add (notify_update_account_queue, info->mail_op);
1627 /* Free thread resources. Will be called after all previous idles */
1628 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1634 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1635 TnyList *header_list,
1636 GetMsgAsyncUserCallback user_callback,
1638 GDestroyNotify notify)
1640 TnyHeader *header = NULL;
1641 TnyFolder *folder = NULL;
1643 ModestMailOperationPrivate *priv = NULL;
1644 GetFullMsgsInfo *info = NULL;
1645 gboolean size_ok = TRUE;
1647 TnyIterator *iter = NULL;
1649 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1651 /* Init mail operation */
1652 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1653 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1655 priv->total = tny_list_get_length(header_list);
1657 /* Get account and set it into mail_operation */
1658 if (tny_list_get_length (header_list) >= 1) {
1659 iter = tny_list_create_iterator (header_list);
1660 header = TNY_HEADER (tny_iterator_get_current (iter));
1661 folder = tny_header_get_folder (header);
1662 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1663 g_object_unref (header);
1664 g_object_unref (folder);
1666 if (tny_list_get_length (header_list) == 1) {
1667 g_object_unref (iter);
1672 /* Get msg size limit */
1673 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1674 MODEST_CONF_MSG_SIZE_LIMIT,
1677 g_clear_error (&(priv->error));
1678 max_size = G_MAXINT;
1680 max_size = max_size * KB;
1683 /* Check message size limits. If there is only one message
1684 always retrieve it */
1686 while (!tny_iterator_is_done (iter) && size_ok) {
1687 header = TNY_HEADER (tny_iterator_get_current (iter));
1688 if (tny_header_get_message_size (header) >= max_size)
1690 g_object_unref (header);
1691 tny_iterator_next (iter);
1693 g_object_unref (iter);
1697 /* Create the info */
1698 info = g_slice_new0 (GetFullMsgsInfo);
1699 info->mail_op = self;
1700 info->user_callback = user_callback;
1701 info->user_data = user_data;
1702 info->headers = g_object_ref (header_list);
1703 info->notify = notify;
1705 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1707 /* Set status failed and set an error */
1708 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1709 /* FIXME: the error msg is different for pop */
1710 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1711 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1712 _("emev_ni_ui_imap_msg_size_exceed_error"));
1713 /* Remove from queue and free resources */
1714 modest_mail_operation_notify_end (self);
1722 modest_mail_operation_remove_msg (ModestMailOperation *self,
1724 gboolean remove_to_trash)
1727 ModestMailOperationPrivate *priv;
1729 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1730 g_return_if_fail (TNY_IS_HEADER (header));
1732 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1733 folder = tny_header_get_folder (header);
1735 /* Get account and set it into mail_operation */
1736 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1738 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1740 /* Delete or move to trash */
1741 if (remove_to_trash) {
1742 TnyFolder *trash_folder;
1743 TnyStoreAccount *store_account;
1745 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1746 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1747 TNY_FOLDER_TYPE_TRASH);
1752 headers = tny_simple_list_new ();
1753 tny_list_append (headers, G_OBJECT (header));
1754 g_object_unref (header);
1757 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1758 g_object_unref (headers);
1759 /* g_object_unref (trash_folder); */
1761 ModestMailOperationPrivate *priv;
1763 /* Set status failed and set an error */
1764 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1766 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1767 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1768 _("Error trying to delete a message. Trash folder not found"));
1771 g_object_unref (G_OBJECT (store_account));
1773 tny_folder_remove_msg (folder, header, &(priv->error));
1775 tny_folder_sync(folder, TRUE, &(priv->error));
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1782 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1785 g_object_unref (G_OBJECT (folder));
1787 /* Notify about operation end */
1788 modest_mail_operation_notify_end (self);
1792 transfer_msgs_status_cb (GObject *obj,
1796 XFerMsgAsyncHelper *helper = NULL;
1797 ModestMailOperation *self;
1798 ModestMailOperationPrivate *priv;
1799 ModestMailOperationState *state;
1802 g_return_if_fail (status != NULL);
1803 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1805 helper = (XFerMsgAsyncHelper *) user_data;
1806 g_return_if_fail (helper != NULL);
1808 self = helper->mail_op;
1809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1811 if ((status->position == 1) && (status->of_total == 100))
1814 priv->done = status->position;
1815 priv->total = status->of_total;
1817 state = modest_mail_operation_clone_state (self);
1818 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1819 g_slice_free (ModestMailOperationState, state);
1824 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1826 XFerMsgAsyncHelper *helper;
1827 ModestMailOperation *self;
1828 ModestMailOperationPrivate *priv;
1830 helper = (XFerMsgAsyncHelper *) user_data;
1831 self = helper->mail_op;
1833 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1836 priv->error = g_error_copy (*err);
1838 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1839 } else if (cancelled) {
1840 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1841 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1842 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1843 _("Error trying to refresh the contents of %s"),
1844 tny_folder_get_name (folder));
1847 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1850 /* If user defined callback function was defined, call it */
1851 if (helper->user_callback) {
1852 helper->user_callback (priv->source, helper->user_data);
1856 g_object_unref (helper->headers);
1857 g_object_unref (helper->dest_folder);
1858 g_object_unref (helper->mail_op);
1859 g_slice_free (XFerMsgAsyncHelper, helper);
1860 g_object_unref (folder);
1862 /* Notify about operation end */
1863 modest_mail_operation_notify_end (self);
1867 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1870 gboolean delete_original,
1871 XferMsgsAsynUserCallback user_callback,
1874 ModestMailOperationPrivate *priv;
1876 TnyFolder *src_folder;
1877 XFerMsgAsyncHelper *helper;
1879 ModestTnyFolderRules rules;
1881 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1882 g_return_if_fail (TNY_IS_LIST (headers));
1883 g_return_if_fail (TNY_IS_FOLDER (folder));
1885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1888 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1890 /* Apply folder rules */
1891 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1893 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1894 /* Set status failed and set an error */
1895 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1896 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1897 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1898 _("FIXME: folder does not accept msgs"));
1899 /* Notify the queue */
1900 modest_mail_operation_notify_end (self);
1904 /* Create the helper */
1905 helper = g_slice_new0 (XFerMsgAsyncHelper);
1906 helper->mail_op = g_object_ref(self);
1907 helper->dest_folder = g_object_ref(folder);
1908 helper->headers = g_object_ref(headers);
1909 helper->user_callback = user_callback;
1910 helper->user_data = user_data;
1912 /* Get source folder */
1913 iter = tny_list_create_iterator (headers);
1914 header = TNY_HEADER (tny_iterator_get_current (iter));
1915 src_folder = tny_header_get_folder (header);
1916 g_object_unref (header);
1917 g_object_unref (iter);
1919 /* Get account and set it into mail_operation */
1920 priv->account = modest_tny_folder_get_account (src_folder);
1922 /* Transfer messages */
1923 tny_folder_transfer_msgs_async (src_folder,
1928 transfer_msgs_status_cb,
1934 on_refresh_folder (TnyFolder *folder,
1939 ModestMailOperation *self;
1940 ModestMailOperationPrivate *priv;
1942 self = MODEST_MAIL_OPERATION (user_data);
1943 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1946 priv->error = g_error_copy (*error);
1947 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1953 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1954 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1955 _("Error trying to refresh the contents of %s"),
1956 tny_folder_get_name (folder));
1960 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1964 g_object_unref (folder);
1966 /* Notify about operation end */
1967 modest_mail_operation_notify_end (self);
1971 on_refresh_folder_status_update (GObject *obj,
1975 ModestMailOperation *self;
1976 ModestMailOperationPrivate *priv;
1977 ModestMailOperationState *state;
1979 g_return_if_fail (status != NULL);
1980 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1982 self = MODEST_MAIL_OPERATION (user_data);
1983 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1985 priv->done = status->position;
1986 priv->total = status->of_total;
1988 state = modest_mail_operation_clone_state (self);
1989 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1990 g_slice_free (ModestMailOperationState, state);
1994 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1997 ModestMailOperationPrivate *priv;
1999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2001 /* Pick a reference */
2002 g_object_ref (folder);
2004 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2006 /* Get account and set it into mail_operation */
2007 priv->account = modest_tny_folder_get_account (folder);
2009 /* Refresh the folder. TODO: tinymail could issue a status
2010 updates before the callback call then this could happen. We
2011 must review the design */
2012 tny_folder_refresh_async (folder,
2014 on_refresh_folder_status_update,
2020 * It's used by the mail operation queue to notify the observers
2021 * attached to that signal that the operation finished. We need to use
2022 * that because tinymail does not give us the progress of a given
2023 * operation when it finishes (it directly calls the operation
2027 modest_mail_operation_notify_end (ModestMailOperation *self)
2029 ModestMailOperationState *state;
2031 /* Notify the observers about the mail opertation end */
2032 state = modest_mail_operation_clone_state (self);
2033 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2034 g_slice_free (ModestMailOperationState, state);