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);
179 modest_mail_operation_init (ModestMailOperation *obj)
181 ModestMailOperationPrivate *priv;
183 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
185 priv->account = NULL;
186 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
187 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
192 priv->error_checking = NULL;
193 priv->error_checking_user_data = NULL;
197 modest_mail_operation_finalize (GObject *obj)
199 ModestMailOperationPrivate *priv;
201 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
204 g_error_free (priv->error);
208 g_object_unref (priv->source);
212 g_object_unref (priv->account);
213 priv->account = NULL;
217 G_OBJECT_CLASS(parent_class)->finalize (obj);
221 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
224 ModestMailOperation *obj;
225 ModestMailOperationPrivate *priv;
227 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
228 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
230 priv->op_type = op_type;
232 priv->source = g_object_ref(source);
238 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
240 ErrorCheckingUserCallback error_handler,
243 ModestMailOperation *obj;
244 ModestMailOperationPrivate *priv;
246 obj = modest_mail_operation_new (op_type, source);
247 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
249 g_return_val_if_fail (error_handler != NULL, obj);
250 priv->error_checking = error_handler;
256 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
258 ModestMailOperationPrivate *priv;
260 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
261 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
263 if (priv->error_checking != NULL)
264 priv->error_checking (self, priv->error_checking_user_data);
268 ModestMailOperationTypeOperation
269 modest_mail_operation_get_type_operation (ModestMailOperation *self)
271 ModestMailOperationPrivate *priv;
273 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
275 return priv->op_type;
279 modest_mail_operation_is_mine (ModestMailOperation *self,
282 ModestMailOperationPrivate *priv;
284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
285 if (priv->source == NULL) return FALSE;
287 return priv->source == me;
291 modest_mail_operation_get_source (ModestMailOperation *self)
293 ModestMailOperationPrivate *priv;
295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
297 return g_object_ref (priv->source);
300 ModestMailOperationStatus
301 modest_mail_operation_get_status (ModestMailOperation *self)
303 ModestMailOperationPrivate *priv;
305 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
306 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
307 MODEST_MAIL_OPERATION_STATUS_INVALID);
309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
314 modest_mail_operation_get_error (ModestMailOperation *self)
316 ModestMailOperationPrivate *priv;
318 g_return_val_if_fail (self, NULL);
319 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
321 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
326 modest_mail_operation_cancel (ModestMailOperation *self)
328 ModestMailOperationPrivate *priv;
330 if (!MODEST_IS_MAIL_OPERATION (self)) {
331 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
335 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
337 /* cancel current operation in account */
338 tny_account_cancel (priv->account);
343 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
345 /* Notify about operation end */
346 modest_mail_operation_notify_end (self);
352 modest_mail_operation_get_task_done (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
363 modest_mail_operation_get_task_total (ModestMailOperation *self)
365 ModestMailOperationPrivate *priv;
367 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
369 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
374 modest_mail_operation_is_finished (ModestMailOperation *self)
376 ModestMailOperationPrivate *priv;
377 gboolean retval = FALSE;
379 if (!MODEST_IS_MAIL_OPERATION (self)) {
380 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
386 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
387 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
388 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
389 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
399 modest_mail_operation_get_id (ModestMailOperation *self)
401 ModestMailOperationPrivate *priv;
403 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
410 modest_mail_operation_set_id (ModestMailOperation *self,
413 ModestMailOperationPrivate *priv;
415 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
422 * Creates an image of the current state of a mail operation, the
423 * caller must free it
425 static ModestMailOperationState *
426 modest_mail_operation_clone_state (ModestMailOperation *self)
428 ModestMailOperationState *state;
429 ModestMailOperationPrivate *priv;
431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
433 state = g_slice_new (ModestMailOperationState);
435 state->status = priv->status;
436 state->op_type = priv->op_type;
437 state->done = priv->done;
438 state->total = priv->total;
439 state->finished = modest_mail_operation_is_finished (self);
444 /* ******************************************************************* */
445 /* ************************** SEND ACTIONS ************************* */
446 /* ******************************************************************* */
449 modest_mail_operation_send_mail (ModestMailOperation *self,
450 TnyTransportAccount *transport_account,
453 TnySendQueue *send_queue = NULL;
454 ModestMailOperationPrivate *priv;
456 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
457 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
458 g_return_if_fail (TNY_IS_MSG (msg));
460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
462 /* Get account and set it into mail_operation */
463 priv->account = g_object_ref (transport_account);
465 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
466 if (!TNY_IS_SEND_QUEUE(send_queue)) {
467 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
468 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
469 "modest: could not find send queue for account\n");
471 tny_send_queue_add (send_queue, msg, &(priv->error));
474 /* Notify about operation end */
475 modest_mail_operation_notify_end (self);
479 modest_mail_operation_send_new_mail (ModestMailOperation *self,
480 TnyTransportAccount *transport_account,
482 const gchar *from, const gchar *to,
483 const gchar *cc, const gchar *bcc,
484 const gchar *subject, const gchar *plain_body,
485 const gchar *html_body,
486 const GList *attachments_list,
487 TnyHeaderFlags priority_flags)
489 TnyMsg *new_msg = NULL;
490 TnyFolder *folder = NULL;
491 TnyHeader *header = NULL;
492 ModestMailOperationPrivate *priv = NULL;
494 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
495 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
499 /* Get account and set it into mail_operation */
500 priv->account = g_object_ref (transport_account);
502 /* Check parametters */
504 /* Set status failed and set an error */
505 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
506 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
507 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
508 _("Error trying to send a mail. You need to set at least one recipient"));
512 if (html_body == NULL) {
513 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
515 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
518 g_printerr ("modest: failed to create a new msg\n");
522 /* Set priority flags in message */
523 header = tny_msg_get_header (new_msg);
524 tny_header_set_flags (header, priority_flags);
526 /* Call mail operation */
527 modest_mail_operation_send_mail (self, transport_account, new_msg);
529 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
531 if (draft_msg != NULL) {
532 header = tny_msg_get_header (draft_msg);
533 /* Note: This can fail (with a warning) if the message is not really already in a folder,
534 * because this function requires it to have a UID. */
535 tny_folder_remove_msg (folder, header, NULL);
536 g_object_unref (header);
541 g_object_unref (G_OBJECT (new_msg));
545 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
546 TnyTransportAccount *transport_account,
548 const gchar *from, const gchar *to,
549 const gchar *cc, const gchar *bcc,
550 const gchar *subject, const gchar *plain_body,
551 const gchar *html_body,
552 const GList *attachments_list,
553 TnyHeaderFlags priority_flags)
556 TnyFolder *folder = NULL;
557 TnyHeader *header = NULL;
558 ModestMailOperationPrivate *priv = NULL;
560 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
561 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
563 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
565 /* Get account and set it into mail_operation */
566 priv->account = g_object_ref (transport_account);
568 if (html_body == NULL) {
569 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
571 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
574 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
575 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
576 "modest: failed to create a new msg\n");
580 /* add priority flags */
581 header = tny_msg_get_header (msg);
582 tny_header_set_flags (header, priority_flags);
584 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
586 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
587 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
588 "modest: failed to create a new msg\n");
592 if (draft_msg != NULL) {
593 header = tny_msg_get_header (draft_msg);
594 tny_folder_remove_msg (folder, header, NULL);
595 g_object_unref (header);
598 tny_folder_add_msg (folder, msg, &(priv->error));
604 g_object_unref (G_OBJECT(msg));
606 g_object_unref (G_OBJECT(folder));
608 modest_mail_operation_notify_end (self);
613 ModestMailOperation *mail_op;
614 TnyStoreAccount *account;
615 TnyTransportAccount *transport_account;
618 gchar *retrieve_type;
621 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
622 /* We use this folder observer to track the headers that have been
623 * added to a folder */
626 TnyList *new_headers;
627 } InternalFolderObserver;
631 } InternalFolderObserverClass;
633 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
635 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
636 internal_folder_observer,
638 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
642 foreach_add_item (gpointer header, gpointer user_data)
644 /* printf("DEBUG: %s: header subject=%s\n",
645 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
647 tny_list_prepend (TNY_LIST (user_data),
648 g_object_ref (G_OBJECT (header)));
651 /* This is the method that looks for new messages in a folder */
653 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
655 InternalFolderObserver *derived = (InternalFolderObserver *)self;
657 TnyFolderChangeChanged changed;
659 changed = tny_folder_change_get_changed (change);
661 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
664 /* Get added headers */
665 list = tny_simple_list_new ();
666 tny_folder_change_get_added_headers (change, list);
668 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
669 * __FUNCTION__, tny_list_get_length(list));
672 /* Add them to the folder observer */
673 tny_list_foreach (list, foreach_add_item,
674 derived->new_headers);
676 g_object_unref (G_OBJECT (list));
681 internal_folder_observer_init (InternalFolderObserver *self)
683 self->new_headers = tny_simple_list_new ();
686 internal_folder_observer_finalize (GObject *object)
688 InternalFolderObserver *self;
690 self = (InternalFolderObserver *) object;
691 g_object_unref (self->new_headers);
693 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
696 tny_folder_observer_init (TnyFolderObserverIface *iface)
698 iface->update_func = internal_folder_observer_update;
701 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
703 GObjectClass *object_class;
705 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
706 object_class = (GObjectClass*) klass;
707 object_class->finalize = internal_folder_observer_finalize;
713 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
716 TnyList *folders = tny_simple_list_new ();
718 tny_folder_store_get_folders (store, folders, query, NULL);
719 iter = tny_list_create_iterator (folders);
721 while (!tny_iterator_is_done (iter)) {
723 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
725 tny_list_prepend (all_folders, G_OBJECT (folder));
726 recurse_folders (folder, query, all_folders);
727 g_object_unref (G_OBJECT (folder));
729 tny_iterator_next (iter);
731 g_object_unref (G_OBJECT (iter));
732 g_object_unref (G_OBJECT (folders));
736 * Issues the "progress-changed" signal. The timer won't be removed,
737 * so you must call g_source_remove to stop the signal emission
740 idle_notify_progress (gpointer data)
742 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
743 ModestMailOperationState *state;
745 state = modest_mail_operation_clone_state (mail_op);
746 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
747 g_slice_free (ModestMailOperationState, state);
753 * Issues the "progress-changed" signal and removes the timer. It uses
754 * a lock to ensure that the progress information of the mail
755 * operation is not modified while there are notifications pending
758 idle_notify_progress_once (gpointer data)
762 pair = (ModestPair *) data;
764 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
766 /* Free the state and the reference to the mail operation */
767 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
768 g_object_unref (pair->first);
774 * Used by update_account_thread to notify the queue from the main
775 * loop. We call it inside an idle call to achieve that
778 notify_update_account_queue (gpointer data)
780 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
781 ModestMailOperationPrivate *priv = NULL;
783 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_op);
785 modest_mail_operation_notify_end (mail_op);
786 g_object_unref (mail_op);
792 compare_headers_by_date (gconstpointer a,
795 TnyHeader **header1, **header2;
798 header1 = (TnyHeader **) a;
799 header2 = (TnyHeader **) b;
801 sent1 = tny_header_get_date_sent (*header1);
802 sent2 = tny_header_get_date_sent (*header2);
804 /* We want the most recent ones (greater time_t) at the
813 update_account_thread (gpointer thr_user_data)
815 UpdateAccountInfo *info;
816 TnyList *all_folders = NULL;
817 GPtrArray *new_headers;
818 TnyIterator *iter = NULL;
819 TnyFolderStoreQuery *query = NULL;
820 ModestMailOperationPrivate *priv;
821 ModestTnySendQueue *send_queue;
824 info = (UpdateAccountInfo *) thr_user_data;
825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
827 /* Get account and set it into mail_operation */
828 priv->account = g_object_ref (info->account);
830 /* Get all the folders. We can do it synchronously because
831 we're already running in a different thread than the UI */
832 all_folders = tny_simple_list_new ();
833 query = tny_folder_store_query_new ();
834 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
835 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
840 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
844 iter = tny_list_create_iterator (all_folders);
845 while (!tny_iterator_is_done (iter)) {
846 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
848 recurse_folders (folder, query, all_folders);
849 tny_iterator_next (iter);
851 g_object_unref (G_OBJECT (iter));
853 /* Update status and notify. We need to call the notification
854 with a source function in order to call it from the main
855 loop. We need that in order not to get into trouble with
856 Gtk+. We use a timeout in order to provide more status
857 information, because the sync tinymail call does not
858 provide it for the moment */
859 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
861 /* Refresh folders */
862 new_headers = g_ptr_array_new ();
863 iter = tny_list_create_iterator (all_folders);
865 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
867 InternalFolderObserver *observer;
868 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
870 /* Refresh the folder */
871 /* Our observer receives notification of new emails during folder refreshes,
872 * so we can use observer->new_headers.
873 * TODO: This does not seem to be providing accurate numbers.
874 * Possibly the observer is notified asynchronously.
876 observer = g_object_new (internal_folder_observer_get_type (), NULL);
877 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
879 /* This gets the status information (headers) from the server.
880 * We use the blocking version, because we are already in a separate
884 /* If the retrieve type is headers only do nothing more */
885 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
886 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
889 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
891 iter = tny_list_create_iterator (observer->new_headers);
892 while (!tny_iterator_is_done (iter)) {
893 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
894 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
895 * __FUNCTION__, tny_account_get_id (priv->account),
896 * tny_header_get_subject (header));
899 /* Apply per-message size limits */
900 if (tny_header_get_message_size (header) < info->max_size)
901 g_ptr_array_add (new_headers, g_object_ref (header));
903 g_object_unref (header);
904 tny_iterator_next (iter);
906 g_object_unref (iter);
908 tny_folder_poke_status (TNY_FOLDER (folder));
910 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
911 g_object_unref (observer);
915 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
917 g_object_unref (G_OBJECT (folder));
918 tny_iterator_next (iter);
921 did_a_cancel = FALSE;
923 g_object_unref (G_OBJECT (iter));
924 g_source_remove (timeout);
926 if (new_headers->len > 0) {
930 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
932 /* Apply message count limit */
933 /* If the number of messages exceeds the maximum, ask the
934 * user to download them all,
935 * as per the UI spec "Retrieval Limits" section in 4.4:
937 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
938 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
939 if (new_headers->len > info->retrieve_limit) {
940 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
941 * with 'Get all' and 'Newest only' buttons. */
942 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
943 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
944 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
945 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
946 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
951 priv->total = MIN (new_headers->len, info->retrieve_limit);
952 while (msg_num < priv->total) {
954 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
955 TnyFolder *folder = tny_header_get_folder (header);
956 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
957 ModestMailOperationState *state;
961 /* We can not just use the mail operation because the
962 values of done and total could change before the
964 state = modest_mail_operation_clone_state (info->mail_op);
965 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
966 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
967 pair, (GDestroyNotify) modest_pair_free);
969 g_object_unref (msg);
970 g_object_unref (folder);
974 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
975 g_ptr_array_free (new_headers, FALSE);
979 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
982 if (priv->account != NULL)
983 g_object_unref (priv->account);
984 priv->account = g_object_ref (info->transport_account);
986 send_queue = modest_runtime_get_send_queue (info->transport_account);
988 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
989 modest_tny_send_queue_try_to_send (send_queue);
990 g_source_remove (timeout);
992 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
993 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
994 "cannot create a send queue for %s\n",
995 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
996 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
999 /* Check if the operation was a success */
1001 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1003 /* Update the last updated key */
1004 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1005 tny_account_get_id (TNY_ACCOUNT (info->account)),
1006 MODEST_ACCOUNT_LAST_UPDATED,
1012 /* Notify about operation end. Note that the info could be
1013 freed before this idle happens, but the mail operation will
1015 g_idle_add (notify_update_account_queue, info->mail_op);
1018 g_object_unref (query);
1019 g_object_unref (all_folders);
1020 g_object_unref (info->account);
1021 g_object_unref (info->transport_account);
1022 g_free (info->retrieve_type);
1023 g_slice_free (UpdateAccountInfo, info);
1029 modest_mail_operation_update_account (ModestMailOperation *self,
1030 const gchar *account_name)
1033 UpdateAccountInfo *info;
1034 ModestMailOperationPrivate *priv;
1035 ModestAccountMgr *mgr;
1036 TnyStoreAccount *modest_account;
1037 TnyTransportAccount *transport_account;
1039 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1040 g_return_val_if_fail (account_name, FALSE);
1042 /* Make sure that we have a connection, and request one
1044 * TODO: Is there some way to trigger this for every attempt to
1045 * use the network? */
1046 if (!modest_platform_connect_and_wait(NULL))
1049 /* Init mail operation. Set total and done to 0, and do not
1050 update them, this way the progress objects will know that
1051 we have no clue about the number of the objects */
1052 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1055 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1057 /* Get the Modest account */
1058 modest_account = (TnyStoreAccount *)
1059 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1061 TNY_ACCOUNT_TYPE_STORE);
1063 if (!modest_account) {
1064 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1065 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1066 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1067 "cannot get tny store account for %s\n", account_name);
1068 modest_mail_operation_notify_end (self);
1073 /* Get the transport account, we can not do it in the thread
1074 due to some problems with dbus */
1075 transport_account = (TnyTransportAccount *)
1076 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1078 if (!transport_account) {
1079 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1080 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1081 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1082 "cannot get tny transport account for %s\n", account_name);
1083 modest_mail_operation_notify_end (self);
1088 /* Create the helper object */
1089 info = g_slice_new (UpdateAccountInfo);
1090 info->mail_op = self;
1091 info->account = modest_account;
1092 info->transport_account = transport_account;
1094 /* Get the message size limit */
1095 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1096 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1097 if (info->max_size == 0)
1098 info->max_size = G_MAXINT;
1100 info->max_size = info->max_size * KB;
1102 /* Get per-account retrieval type */
1103 mgr = modest_runtime_get_account_mgr ();
1104 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1105 MODEST_ACCOUNT_RETRIEVE, FALSE);
1107 /* Get per-account message amount retrieval limit */
1108 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1109 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1110 if (info->retrieve_limit == 0)
1111 info->retrieve_limit = G_MAXINT;
1113 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1115 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1120 /* ******************************************************************* */
1121 /* ************************** STORE ACTIONS ************************* */
1122 /* ******************************************************************* */
1126 modest_mail_operation_create_folder (ModestMailOperation *self,
1127 TnyFolderStore *parent,
1130 ModestMailOperationPrivate *priv;
1131 TnyFolder *new_folder = NULL;
1133 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1134 g_return_val_if_fail (name, NULL);
1136 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1139 if (TNY_IS_FOLDER (parent)) {
1140 /* Check folder rules */
1141 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1142 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1143 /* Set status failed and set an error */
1144 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1145 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1146 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1147 _("mail_in_ui_folder_create_error"));
1152 /* Create the folder */
1153 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1154 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1156 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1159 /* Notify about operation end */
1160 modest_mail_operation_notify_end (self);
1166 modest_mail_operation_remove_folder (ModestMailOperation *self,
1168 gboolean remove_to_trash)
1170 TnyAccount *account;
1171 ModestMailOperationPrivate *priv;
1172 ModestTnyFolderRules rules;
1174 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1175 g_return_if_fail (TNY_IS_FOLDER (folder));
1177 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1179 /* Check folder rules */
1180 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1181 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1182 /* Set status failed and set an error */
1183 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1184 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1185 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1186 _("mail_in_ui_folder_delete_error"));
1190 /* Get the account */
1191 account = modest_tny_folder_get_account (folder);
1192 priv->account = g_object_ref(account);
1194 /* Delete folder or move to trash */
1195 if (remove_to_trash) {
1196 TnyFolder *trash_folder = NULL;
1197 trash_folder = modest_tny_account_get_special_folder (account,
1198 TNY_FOLDER_TYPE_TRASH);
1199 /* TODO: error_handling */
1200 modest_mail_operation_xfer_folder (self, folder,
1201 TNY_FOLDER_STORE (trash_folder), TRUE);
1203 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1205 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1206 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1209 g_object_unref (G_OBJECT (parent));
1211 g_object_unref (G_OBJECT (account));
1214 /* Notify about operation end */
1215 modest_mail_operation_notify_end (self);
1219 transfer_folder_status_cb (GObject *obj,
1223 ModestMailOperation *self;
1224 ModestMailOperationPrivate *priv;
1225 ModestMailOperationState *state;
1227 g_return_if_fail (status != NULL);
1228 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1230 self = MODEST_MAIL_OPERATION (user_data);
1231 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1233 if ((status->position == 1) && (status->of_total == 100))
1236 priv->done = status->position;
1237 priv->total = status->of_total;
1239 state = modest_mail_operation_clone_state (self);
1240 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1241 g_slice_free (ModestMailOperationState, state);
1246 transfer_folder_cb (TnyFolder *folder,
1247 TnyFolderStore *into,
1249 TnyFolder *new_folder, GError **err,
1252 ModestMailOperation *self = NULL;
1253 ModestMailOperationPrivate *priv = NULL;
1255 self = MODEST_MAIL_OPERATION (user_data);
1257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1260 priv->error = g_error_copy (*err);
1262 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1263 } else if (cancelled) {
1264 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1265 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1266 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1267 _("Transference of %s was cancelled."),
1268 tny_folder_get_name (folder));
1271 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1275 g_object_unref (folder);
1276 g_object_unref (into);
1277 if (new_folder != NULL)
1278 g_object_unref (new_folder);
1280 /* Notify about operation end */
1281 modest_mail_operation_notify_end (self);
1285 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1287 TnyFolderStore *parent,
1288 gboolean delete_original)
1290 ModestMailOperationPrivate *priv = NULL;
1291 ModestTnyFolderRules parent_rules, rules;
1293 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1294 g_return_if_fail (TNY_IS_FOLDER (folder));
1295 g_return_if_fail (TNY_IS_FOLDER (parent));
1297 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1299 /* Get account and set it into mail_operation */
1300 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1301 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1303 /* Get folder rules */
1304 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1305 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1307 if (!TNY_IS_FOLDER_STORE (parent)) {
1311 /* The moveable restriction is applied also to copy operation */
1312 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1313 /* Set status failed and set an error */
1314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1315 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1316 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1317 _("mail_in_ui_folder_move_target_error"));
1319 /* Notify the queue */
1320 modest_mail_operation_notify_end (self);
1321 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1322 /* Set status failed and set an error */
1323 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1324 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1325 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1326 _("FIXME: parent folder does not accept new folders"));
1328 /* Notify the queue */
1329 modest_mail_operation_notify_end (self);
1331 /* Pick references for async calls */
1332 g_object_ref (folder);
1333 g_object_ref (parent);
1335 /* Move/Copy folder */
1336 tny_folder_copy_async (folder,
1338 tny_folder_get_name (folder),
1341 transfer_folder_status_cb,
1347 modest_mail_operation_rename_folder (ModestMailOperation *self,
1351 ModestMailOperationPrivate *priv;
1352 ModestTnyFolderRules rules;
1354 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1355 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1356 g_return_if_fail (name);
1358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1360 /* Get account and set it into mail_operation */
1361 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1363 /* Check folder rules */
1364 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1365 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1366 /* Set status failed and set an error */
1367 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1368 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1369 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1370 _("FIXME: unable to rename"));
1372 /* Notify about operation end */
1373 modest_mail_operation_notify_end (self);
1375 /* Rename. Camel handles folder subscription/unsubscription */
1376 TnyFolderStore *into;
1378 into = tny_folder_get_folder_store (folder);
1379 tny_folder_copy_async (folder, into, name, TRUE,
1381 transfer_folder_status_cb,
1384 g_object_unref (into);
1389 /* ******************************************************************* */
1390 /* ************************** MSG ACTIONS ************************* */
1391 /* ******************************************************************* */
1393 void modest_mail_operation_get_msg (ModestMailOperation *self,
1395 GetMsgAsyncUserCallback user_callback,
1398 GetMsgAsyncHelper *helper = NULL;
1400 ModestMailOperationPrivate *priv;
1402 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1403 g_return_if_fail (TNY_IS_HEADER (header));
1405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1406 folder = tny_header_get_folder (header);
1408 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1410 /* Get message from folder */
1412 /* Get account and set it into mail_operation */
1413 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1415 helper = g_slice_new0 (GetMsgAsyncHelper);
1416 helper->mail_op = self;
1417 helper->user_callback = user_callback;
1418 helper->pending_ops = 1;
1419 helper->user_data = user_data;
1421 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1423 g_object_unref (G_OBJECT (folder));
1425 /* Set status failed and set an error */
1426 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1427 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1428 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1429 _("Error trying to get a message. No folder found for header"));
1431 /* Notify the queue */
1432 modest_mail_operation_notify_end (self);
1437 get_msg_cb (TnyFolder *folder,
1443 GetMsgAsyncHelper *helper = NULL;
1444 ModestMailOperation *self = NULL;
1445 ModestMailOperationPrivate *priv = NULL;
1447 helper = (GetMsgAsyncHelper *) user_data;
1448 g_return_if_fail (helper != NULL);
1449 self = helper->mail_op;
1450 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1451 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1453 helper->pending_ops--;
1455 /* Check errors and cancel */
1457 priv->error = g_error_copy (*error);
1458 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1462 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1463 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1464 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1465 _("Error trying to refresh the contents of %s"),
1466 tny_folder_get_name (folder));
1470 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1472 /* If user defined callback function was defined, call it */
1473 if (helper->user_callback) {
1474 helper->user_callback (self, NULL, msg, helper->user_data);
1479 if (helper->pending_ops == 0) {
1480 g_slice_free (GetMsgAsyncHelper, helper);
1482 /* Notify about operation end */
1483 modest_mail_operation_notify_end (self);
1488 get_msg_status_cb (GObject *obj,
1492 GetMsgAsyncHelper *helper = NULL;
1493 ModestMailOperation *self;
1494 ModestMailOperationPrivate *priv;
1495 ModestMailOperationState *state;
1497 g_return_if_fail (status != NULL);
1498 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1500 helper = (GetMsgAsyncHelper *) user_data;
1501 g_return_if_fail (helper != NULL);
1503 self = helper->mail_op;
1504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1506 if ((status->position == 1) && (status->of_total == 100))
1512 state = modest_mail_operation_clone_state (self);
1513 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1514 g_slice_free (ModestMailOperationState, state);
1517 /****************************************************/
1519 ModestMailOperation *mail_op;
1521 GetMsgAsyncUserCallback user_callback;
1523 GDestroyNotify notify;
1527 GetMsgAsyncUserCallback user_callback;
1531 ModestMailOperation *mail_op;
1532 } NotifyGetMsgsInfo;
1536 * Used by get_msgs_full_thread to call the user_callback for each
1537 * message that has been read
1540 notify_get_msgs_full (gpointer data)
1542 NotifyGetMsgsInfo *info;
1544 info = (NotifyGetMsgsInfo *) data;
1546 /* Call the user callback */
1547 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1549 g_slice_free (NotifyGetMsgsInfo, info);
1555 * Used by get_msgs_full_thread to free al the thread resources and to
1556 * call the destroy function for the passed user_data
1559 get_msgs_full_destroyer (gpointer data)
1561 GetFullMsgsInfo *info;
1563 info = (GetFullMsgsInfo *) data;
1566 info->notify (info->user_data);
1569 g_object_unref (info->headers);
1570 g_slice_free (GetFullMsgsInfo, info);
1576 get_msgs_full_thread (gpointer thr_user_data)
1578 GetFullMsgsInfo *info;
1579 ModestMailOperationPrivate *priv = NULL;
1580 TnyIterator *iter = NULL;
1582 info = (GetFullMsgsInfo *) thr_user_data;
1583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1585 iter = tny_list_create_iterator (info->headers);
1586 while (!tny_iterator_is_done (iter)) {
1590 header = TNY_HEADER (tny_iterator_get_current (iter));
1591 folder = tny_header_get_folder (header);
1593 /* Get message from folder */
1596 /* The callback will call it per each header */
1597 msg = tny_folder_get_msg (folder, header, &(priv->error));
1600 ModestMailOperationState *state;
1605 /* notify progress */
1606 state = modest_mail_operation_clone_state (info->mail_op);
1607 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1608 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1609 pair, (GDestroyNotify) modest_pair_free);
1611 /* The callback is the responsible for
1612 freeing the message */
1613 if (info->user_callback) {
1614 NotifyGetMsgsInfo *info_notify;
1615 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1616 info_notify->user_callback = info->user_callback;
1617 info_notify->mail_op = info->mail_op;
1618 info_notify->header = g_object_ref (header);
1619 info_notify->msg = g_object_ref (msg);
1620 info_notify->user_data = info->user_data;
1621 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1622 notify_get_msgs_full,
1625 g_object_unref (msg);
1628 /* Set status failed and set an error */
1629 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1630 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1631 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1632 "Error trying to get a message. No folder found for header");
1634 g_object_unref (header);
1635 tny_iterator_next (iter);
1638 /* Set operation status */
1639 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1642 /* Notify about operation end */
1643 g_idle_add (notify_update_account_queue, info->mail_op);
1645 /* Free thread resources. Will be called after all previous idles */
1646 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1652 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1653 TnyList *header_list,
1654 GetMsgAsyncUserCallback user_callback,
1656 GDestroyNotify notify)
1658 TnyHeader *header = NULL;
1659 TnyFolder *folder = NULL;
1661 ModestMailOperationPrivate *priv = NULL;
1662 GetFullMsgsInfo *info = NULL;
1663 gboolean size_ok = TRUE;
1665 TnyIterator *iter = NULL;
1667 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1669 /* Init mail operation */
1670 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1671 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1673 priv->total = tny_list_get_length(header_list);
1675 /* Get account and set it into mail_operation */
1676 if (tny_list_get_length (header_list) >= 1) {
1677 iter = tny_list_create_iterator (header_list);
1678 header = TNY_HEADER (tny_iterator_get_current (iter));
1679 folder = tny_header_get_folder (header);
1680 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1681 g_object_unref (header);
1682 g_object_unref (folder);
1684 if (tny_list_get_length (header_list) == 1) {
1685 g_object_unref (iter);
1690 /* Get msg size limit */
1691 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1692 MODEST_CONF_MSG_SIZE_LIMIT,
1695 g_clear_error (&(priv->error));
1696 max_size = G_MAXINT;
1698 max_size = max_size * KB;
1701 /* Check message size limits. If there is only one message
1702 always retrieve it */
1704 while (!tny_iterator_is_done (iter) && size_ok) {
1705 header = TNY_HEADER (tny_iterator_get_current (iter));
1706 if (tny_header_get_message_size (header) >= max_size)
1708 g_object_unref (header);
1709 tny_iterator_next (iter);
1711 g_object_unref (iter);
1715 /* Create the info */
1716 info = g_slice_new0 (GetFullMsgsInfo);
1717 info->mail_op = self;
1718 info->user_callback = user_callback;
1719 info->user_data = user_data;
1720 info->headers = g_object_ref (header_list);
1721 info->notify = notify;
1723 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1725 /* Set status failed and set an error */
1726 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1727 /* FIXME: the error msg is different for pop */
1728 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1729 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1730 _("emev_ni_ui_imap_msg_size_exceed_error"));
1731 /* Remove from queue and free resources */
1732 modest_mail_operation_notify_end (self);
1740 modest_mail_operation_remove_msg (ModestMailOperation *self,
1742 gboolean remove_to_trash)
1745 ModestMailOperationPrivate *priv;
1747 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1748 g_return_if_fail (TNY_IS_HEADER (header));
1750 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1751 folder = tny_header_get_folder (header);
1753 /* Get account and set it into mail_operation */
1754 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1756 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1758 /* Delete or move to trash */
1759 if (remove_to_trash) {
1760 TnyFolder *trash_folder;
1761 TnyStoreAccount *store_account;
1763 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1764 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1765 TNY_FOLDER_TYPE_TRASH);
1770 headers = tny_simple_list_new ();
1771 tny_list_append (headers, G_OBJECT (header));
1772 g_object_unref (header);
1775 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1776 g_object_unref (headers);
1777 /* g_object_unref (trash_folder); */
1779 ModestMailOperationPrivate *priv;
1781 /* Set status failed and set an error */
1782 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1783 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1784 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1785 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1786 _("Error trying to delete a message. Trash folder not found"));
1789 g_object_unref (G_OBJECT (store_account));
1791 tny_folder_remove_msg (folder, header, &(priv->error));
1793 tny_folder_sync(folder, TRUE, &(priv->error));
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1803 g_object_unref (G_OBJECT (folder));
1805 /* Notify about operation end */
1806 modest_mail_operation_notify_end (self);
1810 transfer_msgs_status_cb (GObject *obj,
1814 XFerMsgAsyncHelper *helper = NULL;
1815 ModestMailOperation *self;
1816 ModestMailOperationPrivate *priv;
1817 ModestMailOperationState *state;
1820 g_return_if_fail (status != NULL);
1821 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1823 helper = (XFerMsgAsyncHelper *) user_data;
1824 g_return_if_fail (helper != NULL);
1826 self = helper->mail_op;
1827 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1829 if ((status->position == 1) && (status->of_total == 100))
1832 priv->done = status->position;
1833 priv->total = status->of_total;
1835 state = modest_mail_operation_clone_state (self);
1836 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1837 g_slice_free (ModestMailOperationState, state);
1842 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1844 XFerMsgAsyncHelper *helper;
1845 ModestMailOperation *self;
1846 ModestMailOperationPrivate *priv;
1848 helper = (XFerMsgAsyncHelper *) user_data;
1849 self = helper->mail_op;
1851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1854 priv->error = g_error_copy (*err);
1856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1857 } else if (cancelled) {
1858 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1859 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1860 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1861 _("Error trying to refresh the contents of %s"),
1862 tny_folder_get_name (folder));
1865 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1868 /* If user defined callback function was defined, call it */
1869 if (helper->user_callback) {
1870 helper->user_callback (priv->source, helper->user_data);
1874 g_object_unref (helper->headers);
1875 g_object_unref (helper->dest_folder);
1876 g_object_unref (helper->mail_op);
1877 g_slice_free (XFerMsgAsyncHelper, helper);
1878 g_object_unref (folder);
1880 /* Notify about operation end */
1881 modest_mail_operation_notify_end (self);
1885 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1888 gboolean delete_original,
1889 XferMsgsAsynUserCallback user_callback,
1892 ModestMailOperationPrivate *priv;
1894 TnyFolder *src_folder;
1895 XFerMsgAsyncHelper *helper;
1897 ModestTnyFolderRules rules;
1899 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1900 g_return_if_fail (TNY_IS_LIST (headers));
1901 g_return_if_fail (TNY_IS_FOLDER (folder));
1903 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1906 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1908 /* Apply folder rules */
1909 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1911 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1912 /* Set status failed and set an error */
1913 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1914 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1915 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1916 _("FIXME: folder does not accept msgs"));
1917 /* Notify the queue */
1918 modest_mail_operation_notify_end (self);
1922 /* Create the helper */
1923 helper = g_slice_new0 (XFerMsgAsyncHelper);
1924 helper->mail_op = g_object_ref(self);
1925 helper->dest_folder = g_object_ref(folder);
1926 helper->headers = g_object_ref(headers);
1927 helper->user_callback = user_callback;
1928 helper->user_data = user_data;
1930 /* Get source folder */
1931 iter = tny_list_create_iterator (headers);
1932 header = TNY_HEADER (tny_iterator_get_current (iter));
1933 src_folder = tny_header_get_folder (header);
1934 g_object_unref (header);
1935 g_object_unref (iter);
1937 /* Get account and set it into mail_operation */
1938 priv->account = modest_tny_folder_get_account (src_folder);
1940 /* Transfer messages */
1941 tny_folder_transfer_msgs_async (src_folder,
1946 transfer_msgs_status_cb,
1952 on_refresh_folder (TnyFolder *folder,
1957 ModestMailOperation *self;
1958 ModestMailOperationPrivate *priv;
1960 self = MODEST_MAIL_OPERATION (user_data);
1961 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1964 priv->error = g_error_copy (*error);
1965 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1970 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1971 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1972 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1973 _("Error trying to refresh the contents of %s"),
1974 tny_folder_get_name (folder));
1978 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1982 g_object_unref (folder);
1984 /* Notify about operation end */
1985 modest_mail_operation_notify_end (self);
1989 on_refresh_folder_status_update (GObject *obj,
1993 ModestMailOperation *self;
1994 ModestMailOperationPrivate *priv;
1995 ModestMailOperationState *state;
1997 g_return_if_fail (status != NULL);
1998 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2000 self = MODEST_MAIL_OPERATION (user_data);
2001 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2003 priv->done = status->position;
2004 priv->total = status->of_total;
2006 state = modest_mail_operation_clone_state (self);
2007 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2008 g_slice_free (ModestMailOperationState, state);
2012 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2015 ModestMailOperationPrivate *priv;
2017 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2019 /* Pick a reference */
2020 g_object_ref (folder);
2022 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2024 /* Get account and set it into mail_operation */
2025 priv->account = modest_tny_folder_get_account (folder);
2027 /* Refresh the folder. TODO: tinymail could issue a status
2028 updates before the callback call then this could happen. We
2029 must review the design */
2030 tny_folder_refresh_async (folder,
2032 on_refresh_folder_status_update,
2038 * It's used by the mail operation queue to notify the observers
2039 * attached to that signal that the operation finished. We need to use
2040 * that because tinymail does not give us the progress of a given
2041 * operation when it finishes (it directly calls the operation
2045 modest_mail_operation_notify_end (ModestMailOperation *self)
2047 ModestMailOperationState *state;
2049 /* Notify the observers about the mail opertation end */
2050 state = modest_mail_operation_clone_state (self);
2051 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2052 g_slice_free (ModestMailOperationState, state);