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;
823 info = (UpdateAccountInfo *) thr_user_data;
824 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
826 /* Get account and set it into mail_operation */
827 priv->account = g_object_ref (info->account);
829 /* Get all the folders. We can do it synchronously because
830 we're already running in a different thread than the UI */
831 all_folders = tny_simple_list_new ();
832 query = tny_folder_store_query_new ();
833 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
834 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
839 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
843 iter = tny_list_create_iterator (all_folders);
844 while (!tny_iterator_is_done (iter)) {
845 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
847 recurse_folders (folder, query, all_folders);
848 tny_iterator_next (iter);
850 g_object_unref (G_OBJECT (iter));
852 /* Update status and notify. We need to call the notification
853 with a source function in order to call it from the main
854 loop. We need that in order not to get into trouble with
855 Gtk+. We use a timeout in order to provide more status
856 information, because the sync tinymail call does not
857 provide it for the moment */
858 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
860 /* Refresh folders */
861 new_headers = g_ptr_array_new ();
862 iter = tny_list_create_iterator (all_folders);
864 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
866 InternalFolderObserver *observer;
867 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
869 /* Refresh the folder */
870 /* Our observer receives notification of new emails during folder refreshes,
871 * so we can use observer->new_headers.
872 * TODO: This does not seem to be providing accurate numbers.
873 * Possibly the observer is notified asynchronously.
875 observer = g_object_new (internal_folder_observer_get_type (), NULL);
876 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
878 /* This gets the status information (headers) from the server.
879 * We use the blocking version, because we are already in a separate
882 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
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 iter = tny_list_create_iterator (observer->new_headers);
890 while (!tny_iterator_is_done (iter)) {
891 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
892 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
893 * __FUNCTION__, tny_account_get_id (priv->account),
894 * tny_header_get_subject (header));
897 /* Apply per-message size limits */
898 if (tny_header_get_message_size (header) < info->max_size)
899 g_ptr_array_add (new_headers, g_object_ref (header));
901 g_object_unref (header);
902 tny_iterator_next (iter);
904 g_object_unref (iter);
907 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
908 g_object_unref (observer);
912 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
914 g_object_unref (G_OBJECT (folder));
915 tny_iterator_next (iter);
918 did_a_cancel = FALSE;
920 g_object_unref (G_OBJECT (iter));
921 g_source_remove (timeout);
923 if (new_headers->len > 0) {
927 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
929 /* Apply message count limit */
930 /* If the number of messages exceeds the maximum, ask the
931 * user to download them all,
932 * as per the UI spec "Retrieval Limits" section in 4.4:
934 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
935 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
936 if (new_headers->len > info->retrieve_limit) {
937 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
938 * with 'Get all' and 'Newest only' buttons. */
939 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
940 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
941 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
942 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
943 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
948 priv->total = MIN (new_headers->len, info->retrieve_limit);
949 while (msg_num < priv->total) {
951 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
952 TnyFolder *folder = tny_header_get_folder (header);
953 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
954 ModestMailOperationState *state;
958 /* We can not just use the mail operation because the
959 values of done and total could change before the
961 state = modest_mail_operation_clone_state (info->mail_op);
962 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
963 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
964 pair, (GDestroyNotify) modest_pair_free);
966 g_object_unref (msg);
967 g_object_unref (folder);
971 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
972 g_ptr_array_free (new_headers, FALSE);
976 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
979 if (priv->account != NULL)
980 g_object_unref (priv->account);
981 priv->account = g_object_ref (info->transport_account);
983 send_queue = modest_runtime_get_send_queue (info->transport_account);
985 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
986 modest_tny_send_queue_try_to_send (send_queue);
987 g_source_remove (timeout);
989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
990 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
991 "cannot create a send queue for %s\n",
992 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
993 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
996 /* Check if the operation was a success */
998 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1000 /* Update the last updated key */
1001 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1002 tny_account_get_id (TNY_ACCOUNT (info->account)),
1003 MODEST_ACCOUNT_LAST_UPDATED,
1009 /* Notify about operation end. Note that the info could be
1010 freed before this idle happens, but the mail operation will
1012 g_idle_add (notify_update_account_queue, info->mail_op);
1015 g_object_unref (query);
1016 g_object_unref (all_folders);
1017 g_object_unref (info->account);
1018 g_object_unref (info->transport_account);
1019 g_free (info->retrieve_type);
1020 g_slice_free (UpdateAccountInfo, info);
1026 modest_mail_operation_update_account (ModestMailOperation *self,
1027 const gchar *account_name)
1030 UpdateAccountInfo *info;
1031 ModestMailOperationPrivate *priv;
1032 ModestAccountMgr *mgr;
1033 TnyStoreAccount *modest_account;
1034 TnyTransportAccount *transport_account;
1036 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1037 g_return_val_if_fail (account_name, FALSE);
1039 /* Make sure that we have a connection, and request one
1041 * TODO: Is there some way to trigger this for every attempt to
1042 * use the network? */
1043 if (!modest_platform_connect_and_wait(NULL))
1046 /* Init mail operation. Set total and done to 0, and do not
1047 update them, this way the progress objects will know that
1048 we have no clue about the number of the objects */
1049 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1052 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1054 /* Get the Modest account */
1055 modest_account = (TnyStoreAccount *)
1056 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1058 TNY_ACCOUNT_TYPE_STORE);
1060 if (!modest_account) {
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1062 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1063 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1064 "cannot get tny store account for %s\n", account_name);
1065 modest_mail_operation_notify_end (self);
1070 /* Get the transport account, we can not do it in the thread
1071 due to some problems with dbus */
1072 transport_account = (TnyTransportAccount *)
1073 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1075 if (!transport_account) {
1076 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1077 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1078 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1079 "cannot get tny transport account for %s\n", account_name);
1080 modest_mail_operation_notify_end (self);
1085 /* Create the helper object */
1086 info = g_slice_new (UpdateAccountInfo);
1087 info->mail_op = self;
1088 info->account = modest_account;
1089 info->transport_account = transport_account;
1091 /* Get the message size limit */
1092 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1093 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1094 if (info->max_size == 0)
1095 info->max_size = G_MAXINT;
1097 info->max_size = info->max_size * KB;
1099 /* Get per-account retrieval type */
1100 mgr = modest_runtime_get_account_mgr ();
1101 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1102 MODEST_ACCOUNT_RETRIEVE, FALSE);
1104 /* Get per-account message amount retrieval limit */
1105 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1106 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1107 if (info->retrieve_limit == 0)
1108 info->retrieve_limit = G_MAXINT;
1110 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1112 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1117 /* ******************************************************************* */
1118 /* ************************** STORE ACTIONS ************************* */
1119 /* ******************************************************************* */
1123 modest_mail_operation_create_folder (ModestMailOperation *self,
1124 TnyFolderStore *parent,
1127 ModestMailOperationPrivate *priv;
1128 TnyFolder *new_folder = NULL;
1130 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1131 g_return_val_if_fail (name, NULL);
1133 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1136 if (TNY_IS_FOLDER (parent)) {
1137 /* Check folder rules */
1138 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1139 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1140 /* Set status failed and set an error */
1141 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1142 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1143 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1144 _("mail_in_ui_folder_create_error"));
1149 /* Create the folder */
1150 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1151 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1153 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1156 /* Notify about operation end */
1157 modest_mail_operation_notify_end (self);
1163 modest_mail_operation_remove_folder (ModestMailOperation *self,
1165 gboolean remove_to_trash)
1167 TnyAccount *account;
1168 ModestMailOperationPrivate *priv;
1169 ModestTnyFolderRules rules;
1171 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1172 g_return_if_fail (TNY_IS_FOLDER (folder));
1174 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1176 /* Check folder rules */
1177 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1178 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1179 /* Set status failed and set an error */
1180 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1181 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1182 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1183 _("mail_in_ui_folder_delete_error"));
1187 /* Get the account */
1188 account = modest_tny_folder_get_account (folder);
1189 priv->account = g_object_ref(account);
1191 /* Delete folder or move to trash */
1192 if (remove_to_trash) {
1193 TnyFolder *trash_folder = NULL;
1194 trash_folder = modest_tny_account_get_special_folder (account,
1195 TNY_FOLDER_TYPE_TRASH);
1196 /* TODO: error_handling */
1197 modest_mail_operation_xfer_folder (self, folder,
1198 TNY_FOLDER_STORE (trash_folder), TRUE);
1200 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1202 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1203 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1206 g_object_unref (G_OBJECT (parent));
1208 g_object_unref (G_OBJECT (account));
1211 /* Notify about operation end */
1212 modest_mail_operation_notify_end (self);
1216 transfer_folder_status_cb (GObject *obj,
1220 ModestMailOperation *self;
1221 ModestMailOperationPrivate *priv;
1222 ModestMailOperationState *state;
1224 g_return_if_fail (status != NULL);
1225 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1227 self = MODEST_MAIL_OPERATION (user_data);
1228 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1230 if ((status->position == 1) && (status->of_total == 100))
1233 priv->done = status->position;
1234 priv->total = status->of_total;
1236 state = modest_mail_operation_clone_state (self);
1237 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1238 g_slice_free (ModestMailOperationState, state);
1243 transfer_folder_cb (TnyFolder *folder,
1244 TnyFolderStore *into,
1246 TnyFolder *new_folder, GError **err,
1249 ModestMailOperation *self = NULL;
1250 ModestMailOperationPrivate *priv = NULL;
1252 self = MODEST_MAIL_OPERATION (user_data);
1254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1257 priv->error = g_error_copy (*err);
1259 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1260 } else if (cancelled) {
1261 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1262 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1263 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1264 _("Transference of %s was cancelled."),
1265 tny_folder_get_name (folder));
1268 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1272 g_object_unref (folder);
1273 g_object_unref (into);
1274 if (new_folder != NULL)
1275 g_object_unref (new_folder);
1277 /* Notify about operation end */
1278 modest_mail_operation_notify_end (self);
1282 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1284 TnyFolderStore *parent,
1285 gboolean delete_original)
1287 ModestMailOperationPrivate *priv = NULL;
1288 ModestTnyFolderRules parent_rules, rules;
1290 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1291 g_return_if_fail (TNY_IS_FOLDER (folder));
1292 g_return_if_fail (TNY_IS_FOLDER (parent));
1294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1296 /* Get account and set it into mail_operation */
1297 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1298 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1300 /* Get folder rules */
1301 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1302 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1304 if (!TNY_IS_FOLDER_STORE (parent)) {
1308 /* The moveable restriction is applied also to copy operation */
1309 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1310 /* Set status failed and set an error */
1311 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1312 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1313 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1314 _("mail_in_ui_folder_move_target_error"));
1316 /* Notify the queue */
1317 modest_mail_operation_notify_end (self);
1318 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1319 /* Set status failed and set an error */
1320 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1321 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1322 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1323 _("FIXME: parent folder does not accept new folders"));
1325 /* Notify the queue */
1326 modest_mail_operation_notify_end (self);
1328 /* Pick references for async calls */
1329 g_object_ref (folder);
1330 g_object_ref (parent);
1332 /* Move/Copy folder */
1333 tny_folder_copy_async (folder,
1335 tny_folder_get_name (folder),
1338 transfer_folder_status_cb,
1344 modest_mail_operation_rename_folder (ModestMailOperation *self,
1348 ModestMailOperationPrivate *priv;
1349 ModestTnyFolderRules rules;
1351 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1352 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1353 g_return_if_fail (name);
1355 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1357 /* Get account and set it into mail_operation */
1358 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1360 /* Check folder rules */
1361 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1362 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1363 /* Set status failed and set an error */
1364 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1365 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1366 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1367 _("FIXME: unable to rename"));
1369 /* Notify about operation end */
1370 modest_mail_operation_notify_end (self);
1372 /* Rename. Camel handles folder subscription/unsubscription */
1373 TnyFolderStore *into;
1375 into = tny_folder_get_folder_store (folder);
1376 tny_folder_copy_async (folder, into, name, TRUE,
1378 transfer_folder_status_cb,
1381 g_object_unref (into);
1386 /* ******************************************************************* */
1387 /* ************************** MSG ACTIONS ************************* */
1388 /* ******************************************************************* */
1390 void modest_mail_operation_get_msg (ModestMailOperation *self,
1392 GetMsgAsyncUserCallback user_callback,
1395 GetMsgAsyncHelper *helper = NULL;
1397 ModestMailOperationPrivate *priv;
1399 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1400 g_return_if_fail (TNY_IS_HEADER (header));
1402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1403 folder = tny_header_get_folder (header);
1405 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1407 /* Get message from folder */
1409 /* Get account and set it into mail_operation */
1410 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1412 helper = g_slice_new0 (GetMsgAsyncHelper);
1413 helper->mail_op = self;
1414 helper->user_callback = user_callback;
1415 helper->pending_ops = 1;
1416 helper->user_data = user_data;
1418 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1420 g_object_unref (G_OBJECT (folder));
1422 /* Set status failed and set an error */
1423 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1424 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1425 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1426 _("Error trying to get a message. No folder found for header"));
1428 /* Notify the queue */
1429 modest_mail_operation_notify_end (self);
1434 get_msg_cb (TnyFolder *folder,
1440 GetMsgAsyncHelper *helper = NULL;
1441 ModestMailOperation *self = NULL;
1442 ModestMailOperationPrivate *priv = NULL;
1444 helper = (GetMsgAsyncHelper *) user_data;
1445 g_return_if_fail (helper != NULL);
1446 self = helper->mail_op;
1447 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1450 helper->pending_ops--;
1452 /* Check errors and cancel */
1454 priv->error = g_error_copy (*error);
1455 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1459 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1460 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1461 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1462 _("Error trying to refresh the contents of %s"),
1463 tny_folder_get_name (folder));
1467 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1469 /* If user defined callback function was defined, call it */
1470 if (helper->user_callback) {
1471 helper->user_callback (self, NULL, msg, helper->user_data);
1476 if (helper->pending_ops == 0) {
1477 g_slice_free (GetMsgAsyncHelper, helper);
1479 /* Notify about operation end */
1480 modest_mail_operation_notify_end (self);
1485 get_msg_status_cb (GObject *obj,
1489 GetMsgAsyncHelper *helper = NULL;
1490 ModestMailOperation *self;
1491 ModestMailOperationPrivate *priv;
1492 ModestMailOperationState *state;
1494 g_return_if_fail (status != NULL);
1495 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1497 helper = (GetMsgAsyncHelper *) user_data;
1498 g_return_if_fail (helper != NULL);
1500 self = helper->mail_op;
1501 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1503 if ((status->position == 1) && (status->of_total == 100))
1509 state = modest_mail_operation_clone_state (self);
1510 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1511 g_slice_free (ModestMailOperationState, state);
1514 /****************************************************/
1516 ModestMailOperation *mail_op;
1518 GetMsgAsyncUserCallback user_callback;
1520 GDestroyNotify notify;
1524 GetMsgAsyncUserCallback user_callback;
1528 ModestMailOperation *mail_op;
1529 } NotifyGetMsgsInfo;
1533 * Used by get_msgs_full_thread to call the user_callback for each
1534 * message that has been read
1537 notify_get_msgs_full (gpointer data)
1539 NotifyGetMsgsInfo *info;
1541 info = (NotifyGetMsgsInfo *) data;
1543 /* Call the user callback */
1544 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1546 g_slice_free (NotifyGetMsgsInfo, info);
1552 * Used by get_msgs_full_thread to free al the thread resources and to
1553 * call the destroy function for the passed user_data
1556 get_msgs_full_destroyer (gpointer data)
1558 GetFullMsgsInfo *info;
1560 info = (GetFullMsgsInfo *) data;
1563 info->notify (info->user_data);
1566 g_object_unref (info->headers);
1567 g_slice_free (GetFullMsgsInfo, info);
1573 get_msgs_full_thread (gpointer thr_user_data)
1575 GetFullMsgsInfo *info;
1576 ModestMailOperationPrivate *priv = NULL;
1577 TnyIterator *iter = NULL;
1579 info = (GetFullMsgsInfo *) thr_user_data;
1580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1582 iter = tny_list_create_iterator (info->headers);
1583 while (!tny_iterator_is_done (iter)) {
1587 header = TNY_HEADER (tny_iterator_get_current (iter));
1588 folder = tny_header_get_folder (header);
1590 /* Get message from folder */
1593 /* The callback will call it per each header */
1594 msg = tny_folder_get_msg (folder, header, &(priv->error));
1597 ModestMailOperationState *state;
1602 /* notify progress */
1603 state = modest_mail_operation_clone_state (info->mail_op);
1604 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1605 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1606 pair, (GDestroyNotify) modest_pair_free);
1608 /* The callback is the responsible for
1609 freeing the message */
1610 if (info->user_callback) {
1611 NotifyGetMsgsInfo *info_notify;
1612 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1613 info_notify->user_callback = info->user_callback;
1614 info_notify->mail_op = info->mail_op;
1615 info_notify->header = g_object_ref (header);
1616 info_notify->msg = g_object_ref (msg);
1617 info_notify->user_data = info->user_data;
1618 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1619 notify_get_msgs_full,
1622 g_object_unref (msg);
1625 /* Set status failed and set an error */
1626 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1627 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1628 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1629 "Error trying to get a message. No folder found for header");
1631 g_object_unref (header);
1632 tny_iterator_next (iter);
1635 /* Set operation status */
1636 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1637 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1639 /* Notify about operation end */
1640 g_idle_add (notify_update_account_queue, info->mail_op);
1642 /* Free thread resources. Will be called after all previous idles */
1643 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1649 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1650 TnyList *header_list,
1651 GetMsgAsyncUserCallback user_callback,
1653 GDestroyNotify notify)
1655 TnyHeader *header = NULL;
1656 TnyFolder *folder = NULL;
1658 ModestMailOperationPrivate *priv = NULL;
1659 GetFullMsgsInfo *info = NULL;
1660 gboolean size_ok = TRUE;
1662 TnyIterator *iter = NULL;
1664 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1666 /* Init mail operation */
1667 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1668 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1670 priv->total = tny_list_get_length(header_list);
1672 /* Get account and set it into mail_operation */
1673 if (tny_list_get_length (header_list) >= 1) {
1674 iter = tny_list_create_iterator (header_list);
1675 header = TNY_HEADER (tny_iterator_get_current (iter));
1676 folder = tny_header_get_folder (header);
1677 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1678 g_object_unref (header);
1679 g_object_unref (folder);
1681 if (tny_list_get_length (header_list) == 1) {
1682 g_object_unref (iter);
1687 /* Get msg size limit */
1688 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1689 MODEST_CONF_MSG_SIZE_LIMIT,
1692 g_clear_error (&(priv->error));
1693 max_size = G_MAXINT;
1695 max_size = max_size * KB;
1698 /* Check message size limits. If there is only one message
1699 always retrieve it */
1701 while (!tny_iterator_is_done (iter) && size_ok) {
1702 header = TNY_HEADER (tny_iterator_get_current (iter));
1703 if (tny_header_get_message_size (header) >= max_size)
1705 g_object_unref (header);
1706 tny_iterator_next (iter);
1708 g_object_unref (iter);
1712 /* Create the info */
1713 info = g_slice_new0 (GetFullMsgsInfo);
1714 info->mail_op = self;
1715 info->user_callback = user_callback;
1716 info->user_data = user_data;
1717 info->headers = g_object_ref (header_list);
1718 info->notify = notify;
1720 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1722 /* Set status failed and set an error */
1723 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1724 /* FIXME: the error msg is different for pop */
1725 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1726 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1727 _("emev_ni_ui_imap_msg_size_exceed_error"));
1728 /* Remove from queue and free resources */
1729 modest_mail_operation_notify_end (self);
1737 modest_mail_operation_remove_msg (ModestMailOperation *self,
1739 gboolean remove_to_trash)
1742 ModestMailOperationPrivate *priv;
1744 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1745 g_return_if_fail (TNY_IS_HEADER (header));
1747 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1748 folder = tny_header_get_folder (header);
1750 /* Get account and set it into mail_operation */
1751 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1755 /* Delete or move to trash */
1756 if (remove_to_trash) {
1757 TnyFolder *trash_folder;
1758 TnyStoreAccount *store_account;
1760 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1761 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1762 TNY_FOLDER_TYPE_TRASH);
1767 headers = tny_simple_list_new ();
1768 tny_list_append (headers, G_OBJECT (header));
1769 g_object_unref (header);
1772 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1773 g_object_unref (headers);
1774 /* g_object_unref (trash_folder); */
1776 ModestMailOperationPrivate *priv;
1778 /* Set status failed and set an error */
1779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1781 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1782 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1783 _("Error trying to delete a message. Trash folder not found"));
1786 g_object_unref (G_OBJECT (store_account));
1788 tny_folder_remove_msg (folder, header, &(priv->error));
1790 tny_folder_sync(folder, TRUE, &(priv->error));
1795 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1797 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1800 g_object_unref (G_OBJECT (folder));
1802 /* Notify about operation end */
1803 modest_mail_operation_notify_end (self);
1807 transfer_msgs_status_cb (GObject *obj,
1811 XFerMsgAsyncHelper *helper = NULL;
1812 ModestMailOperation *self;
1813 ModestMailOperationPrivate *priv;
1814 ModestMailOperationState *state;
1817 g_return_if_fail (status != NULL);
1818 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1820 helper = (XFerMsgAsyncHelper *) user_data;
1821 g_return_if_fail (helper != NULL);
1823 self = helper->mail_op;
1824 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1826 if ((status->position == 1) && (status->of_total == 100))
1829 priv->done = status->position;
1830 priv->total = status->of_total;
1832 state = modest_mail_operation_clone_state (self);
1833 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1834 g_slice_free (ModestMailOperationState, state);
1839 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1841 XFerMsgAsyncHelper *helper;
1842 ModestMailOperation *self;
1843 ModestMailOperationPrivate *priv;
1845 helper = (XFerMsgAsyncHelper *) user_data;
1846 self = helper->mail_op;
1848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1851 priv->error = g_error_copy (*err);
1853 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1854 } else if (cancelled) {
1855 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1856 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1857 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1858 _("Error trying to refresh the contents of %s"),
1859 tny_folder_get_name (folder));
1862 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1865 /* If user defined callback function was defined, call it */
1866 if (helper->user_callback) {
1867 helper->user_callback (priv->source, helper->user_data);
1871 g_object_unref (helper->headers);
1872 g_object_unref (helper->dest_folder);
1873 g_object_unref (helper->mail_op);
1874 g_slice_free (XFerMsgAsyncHelper, helper);
1875 g_object_unref (folder);
1877 /* Notify about operation end */
1878 modest_mail_operation_notify_end (self);
1882 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1885 gboolean delete_original,
1886 XferMsgsAsynUserCallback user_callback,
1889 ModestMailOperationPrivate *priv;
1891 TnyFolder *src_folder;
1892 XFerMsgAsyncHelper *helper;
1894 ModestTnyFolderRules rules;
1896 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1897 g_return_if_fail (TNY_IS_LIST (headers));
1898 g_return_if_fail (TNY_IS_FOLDER (folder));
1900 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1903 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1905 /* Apply folder rules */
1906 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1908 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1909 /* Set status failed and set an error */
1910 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1911 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1912 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1913 _("FIXME: folder does not accept msgs"));
1914 /* Notify the queue */
1915 modest_mail_operation_notify_end (self);
1919 /* Create the helper */
1920 helper = g_slice_new0 (XFerMsgAsyncHelper);
1921 helper->mail_op = g_object_ref(self);
1922 helper->dest_folder = g_object_ref(folder);
1923 helper->headers = g_object_ref(headers);
1924 helper->user_callback = user_callback;
1925 helper->user_data = user_data;
1927 /* Get source folder */
1928 iter = tny_list_create_iterator (headers);
1929 header = TNY_HEADER (tny_iterator_get_current (iter));
1930 src_folder = tny_header_get_folder (header);
1931 g_object_unref (header);
1932 g_object_unref (iter);
1934 /* Get account and set it into mail_operation */
1935 priv->account = modest_tny_folder_get_account (src_folder);
1937 /* Transfer messages */
1938 tny_folder_transfer_msgs_async (src_folder,
1943 transfer_msgs_status_cb,
1949 on_refresh_folder (TnyFolder *folder,
1954 ModestMailOperation *self;
1955 ModestMailOperationPrivate *priv;
1957 self = MODEST_MAIL_OPERATION (user_data);
1958 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1961 priv->error = g_error_copy (*error);
1962 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1967 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1968 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1969 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1970 _("Error trying to refresh the contents of %s"),
1971 tny_folder_get_name (folder));
1975 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1979 g_object_unref (folder);
1981 /* Notify about operation end */
1982 modest_mail_operation_notify_end (self);
1986 on_refresh_folder_status_update (GObject *obj,
1990 ModestMailOperation *self;
1991 ModestMailOperationPrivate *priv;
1992 ModestMailOperationState *state;
1994 g_return_if_fail (status != NULL);
1995 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1997 self = MODEST_MAIL_OPERATION (user_data);
1998 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2000 priv->done = status->position;
2001 priv->total = status->of_total;
2003 state = modest_mail_operation_clone_state (self);
2004 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2005 g_slice_free (ModestMailOperationState, state);
2009 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2012 ModestMailOperationPrivate *priv;
2014 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2016 /* Pick a reference */
2017 g_object_ref (folder);
2019 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2021 /* Get account and set it into mail_operation */
2022 priv->account = modest_tny_folder_get_account (folder);
2024 /* Refresh the folder. TODO: tinymail could issue a status
2025 updates before the callback call then this could happen. We
2026 must review the design */
2027 tny_folder_refresh_async (folder,
2029 on_refresh_folder_status_update,
2035 * It's used by the mail operation queue to notify the observers
2036 * attached to that signal that the operation finished. We need to use
2037 * that because tinymail does not give us the progress of a given
2038 * operation when it finishes (it directly calls the operation
2042 modest_mail_operation_notify_end (ModestMailOperation *self)
2044 ModestMailOperationState *state;
2046 /* Notify the observers about the mail opertation end */
2047 state = modest_mail_operation_clone_state (self);
2048 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2049 g_slice_free (ModestMailOperationState, state);