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 set_last_updated_idle (gpointer data)
815 /* It does not matter if the time is not exactly the same than
816 the time when this idle was called, it's just an
817 approximation and it won't be very different */
818 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
820 MODEST_ACCOUNT_LAST_UPDATED,
828 update_account_thread (gpointer thr_user_data)
830 UpdateAccountInfo *info;
831 TnyList *all_folders = NULL;
832 GPtrArray *new_headers;
833 TnyIterator *iter = NULL;
834 TnyFolderStoreQuery *query = NULL;
835 ModestMailOperationPrivate *priv;
836 ModestTnySendQueue *send_queue;
839 info = (UpdateAccountInfo *) thr_user_data;
840 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
842 /* Get account and set it into mail_operation */
843 priv->account = g_object_ref (info->account);
845 /* Get all the folders. We can do it synchronously because
846 we're already running in a different thread than the UI */
847 all_folders = tny_simple_list_new ();
848 query = tny_folder_store_query_new ();
849 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
850 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
855 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
859 iter = tny_list_create_iterator (all_folders);
860 while (!tny_iterator_is_done (iter)) {
861 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
863 recurse_folders (folder, query, all_folders);
864 tny_iterator_next (iter);
866 g_object_unref (G_OBJECT (iter));
868 /* Update status and notify. We need to call the notification
869 with a source function in order to call it from the main
870 loop. We need that in order not to get into trouble with
871 Gtk+. We use a timeout in order to provide more status
872 information, because the sync tinymail call does not
873 provide it for the moment */
874 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
876 /* Refresh folders */
877 new_headers = g_ptr_array_new ();
878 iter = tny_list_create_iterator (all_folders);
880 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
882 InternalFolderObserver *observer;
883 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
885 /* Refresh the folder */
886 /* Our observer receives notification of new emails during folder refreshes,
887 * so we can use observer->new_headers.
888 * TODO: This does not seem to be providing accurate numbers.
889 * Possibly the observer is notified asynchronously.
891 observer = g_object_new (internal_folder_observer_get_type (), NULL);
892 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
894 /* This gets the status information (headers) from the server.
895 * We use the blocking version, because we are already in a separate
899 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
900 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
903 /* If the retrieve type is full messages, refresh and get the messages */
904 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
906 iter = tny_list_create_iterator (observer->new_headers);
907 while (!tny_iterator_is_done (iter)) {
908 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
909 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
910 * __FUNCTION__, tny_account_get_id (priv->account),
911 * tny_header_get_subject (header));
914 /* Apply per-message size limits */
915 if (tny_header_get_message_size (header) < info->max_size)
916 g_ptr_array_add (new_headers, g_object_ref (header));
918 g_object_unref (header);
919 tny_iterator_next (iter);
921 g_object_unref (iter);
922 } else /* If it's headers only, then just poke the folder status (this will update the unread and total count of folder observers, like the folder list model*/
923 tny_folder_poke_status (TNY_FOLDER (folder));
925 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
926 g_object_unref (observer);
930 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
932 g_object_unref (G_OBJECT (folder));
933 tny_iterator_next (iter);
936 did_a_cancel = FALSE;
938 g_object_unref (G_OBJECT (iter));
939 g_source_remove (timeout);
941 if (new_headers->len > 0) {
945 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
947 /* Apply message count limit */
948 /* If the number of messages exceeds the maximum, ask the
949 * user to download them all,
950 * as per the UI spec "Retrieval Limits" section in 4.4:
952 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
953 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
954 if (new_headers->len > info->retrieve_limit) {
955 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
956 * with 'Get all' and 'Newest only' buttons. */
957 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
958 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
959 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
960 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
961 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
966 priv->total = MIN (new_headers->len, info->retrieve_limit);
967 while (msg_num < priv->total) {
969 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
970 TnyFolder *folder = tny_header_get_folder (header);
971 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
972 ModestMailOperationState *state;
976 /* We can not just use the mail operation because the
977 values of done and total could change before the
979 state = modest_mail_operation_clone_state (info->mail_op);
980 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
981 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
982 pair, (GDestroyNotify) modest_pair_free);
984 g_object_unref (msg);
985 g_object_unref (folder);
989 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
990 g_ptr_array_free (new_headers, FALSE);
994 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
997 if (priv->account != NULL)
998 g_object_unref (priv->account);
999 priv->account = g_object_ref (info->transport_account);
1001 send_queue = modest_runtime_get_send_queue (info->transport_account);
1003 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
1004 modest_tny_send_queue_try_to_send (send_queue);
1005 g_source_remove (timeout);
1007 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1008 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1009 "cannot create a send queue for %s\n",
1010 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1011 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1014 /* Check if the operation was a success */
1016 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1018 /* Update the last updated key */
1019 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1020 set_last_updated_idle,
1021 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1022 (GDestroyNotify) g_free);
1026 /* Notify about operation end. Note that the info could be
1027 freed before this idle happens, but the mail operation will
1029 g_idle_add (notify_update_account_queue, info->mail_op);
1032 g_object_unref (query);
1033 g_object_unref (all_folders);
1034 g_object_unref (info->account);
1035 g_object_unref (info->transport_account);
1036 g_free (info->retrieve_type);
1037 g_slice_free (UpdateAccountInfo, info);
1043 modest_mail_operation_update_account (ModestMailOperation *self,
1044 const gchar *account_name)
1047 UpdateAccountInfo *info;
1048 ModestMailOperationPrivate *priv;
1049 ModestAccountMgr *mgr;
1050 TnyStoreAccount *modest_account;
1051 TnyTransportAccount *transport_account;
1053 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1054 g_return_val_if_fail (account_name, FALSE);
1056 /* Make sure that we have a connection, and request one
1058 * TODO: Is there some way to trigger this for every attempt to
1059 * use the network? */
1060 if (!modest_platform_connect_and_wait(NULL))
1063 /* Init mail operation. Set total and done to 0, and do not
1064 update them, this way the progress objects will know that
1065 we have no clue about the number of the objects */
1066 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1069 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1071 /* Get the Modest account */
1072 modest_account = (TnyStoreAccount *)
1073 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1075 TNY_ACCOUNT_TYPE_STORE);
1077 if (!modest_account) {
1078 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1079 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1080 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1081 "cannot get tny store account for %s\n", account_name);
1082 modest_mail_operation_notify_end (self);
1087 /* Get the transport account, we can not do it in the thread
1088 due to some problems with dbus */
1089 transport_account = (TnyTransportAccount *)
1090 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1092 if (!transport_account) {
1093 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1094 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1095 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1096 "cannot get tny transport account for %s\n", account_name);
1097 modest_mail_operation_notify_end (self);
1102 /* Create the helper object */
1103 info = g_slice_new (UpdateAccountInfo);
1104 info->mail_op = self;
1105 info->account = modest_account;
1106 info->transport_account = transport_account;
1108 /* Get the message size limit */
1109 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1110 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1111 if (info->max_size == 0)
1112 info->max_size = G_MAXINT;
1114 info->max_size = info->max_size * KB;
1116 /* Get per-account retrieval type */
1117 mgr = modest_runtime_get_account_mgr ();
1118 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1119 MODEST_ACCOUNT_RETRIEVE, FALSE);
1121 /* Get per-account message amount retrieval limit */
1122 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1123 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1124 if (info->retrieve_limit == 0)
1125 info->retrieve_limit = G_MAXINT;
1127 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1129 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1134 /* ******************************************************************* */
1135 /* ************************** STORE ACTIONS ************************* */
1136 /* ******************************************************************* */
1140 modest_mail_operation_create_folder (ModestMailOperation *self,
1141 TnyFolderStore *parent,
1144 ModestMailOperationPrivate *priv;
1145 TnyFolder *new_folder = NULL;
1147 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1148 g_return_val_if_fail (name, NULL);
1150 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1153 if (TNY_IS_FOLDER (parent)) {
1154 /* Check folder rules */
1155 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1156 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1157 /* Set status failed and set an error */
1158 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1159 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1160 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1161 _("mail_in_ui_folder_create_error"));
1166 /* Create the folder */
1167 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1168 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1170 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1173 /* Notify about operation end */
1174 modest_mail_operation_notify_end (self);
1180 modest_mail_operation_remove_folder (ModestMailOperation *self,
1182 gboolean remove_to_trash)
1184 TnyAccount *account;
1185 ModestMailOperationPrivate *priv;
1186 ModestTnyFolderRules rules;
1188 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1189 g_return_if_fail (TNY_IS_FOLDER (folder));
1191 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1193 /* Check folder rules */
1194 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1195 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1196 /* Set status failed and set an error */
1197 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1198 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1199 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1200 _("mail_in_ui_folder_delete_error"));
1204 /* Get the account */
1205 account = modest_tny_folder_get_account (folder);
1206 priv->account = g_object_ref(account);
1208 /* Delete folder or move to trash */
1209 if (remove_to_trash) {
1210 TnyFolder *trash_folder = NULL;
1211 trash_folder = modest_tny_account_get_special_folder (account,
1212 TNY_FOLDER_TYPE_TRASH);
1213 /* TODO: error_handling */
1214 modest_mail_operation_xfer_folder (self, folder,
1215 TNY_FOLDER_STORE (trash_folder), TRUE);
1217 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1219 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1220 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1223 g_object_unref (G_OBJECT (parent));
1225 g_object_unref (G_OBJECT (account));
1228 /* Notify about operation end */
1229 modest_mail_operation_notify_end (self);
1233 transfer_folder_status_cb (GObject *obj,
1237 ModestMailOperation *self;
1238 ModestMailOperationPrivate *priv;
1239 ModestMailOperationState *state;
1241 g_return_if_fail (status != NULL);
1242 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1244 self = MODEST_MAIL_OPERATION (user_data);
1245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1247 if ((status->position == 1) && (status->of_total == 100))
1250 priv->done = status->position;
1251 priv->total = status->of_total;
1253 state = modest_mail_operation_clone_state (self);
1254 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1255 g_slice_free (ModestMailOperationState, state);
1260 transfer_folder_cb (TnyFolder *folder,
1261 TnyFolderStore *into,
1263 TnyFolder *new_folder, GError **err,
1266 ModestMailOperation *self = NULL;
1267 ModestMailOperationPrivate *priv = NULL;
1269 self = MODEST_MAIL_OPERATION (user_data);
1271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1274 priv->error = g_error_copy (*err);
1276 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1277 } else if (cancelled) {
1278 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1279 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1280 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1281 _("Transference of %s was cancelled."),
1282 tny_folder_get_name (folder));
1285 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1289 g_object_unref (folder);
1290 g_object_unref (into);
1291 if (new_folder != NULL)
1292 g_object_unref (new_folder);
1294 /* Notify about operation end */
1295 modest_mail_operation_notify_end (self);
1299 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1301 TnyFolderStore *parent,
1302 gboolean delete_original)
1304 ModestMailOperationPrivate *priv = NULL;
1305 ModestTnyFolderRules parent_rules, rules;
1307 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1308 g_return_if_fail (TNY_IS_FOLDER (folder));
1309 g_return_if_fail (TNY_IS_FOLDER (parent));
1311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1313 /* Get account and set it into mail_operation */
1314 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1315 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1317 /* Get folder rules */
1318 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1319 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1321 if (!TNY_IS_FOLDER_STORE (parent)) {
1325 /* The moveable restriction is applied also to copy operation */
1326 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1327 /* Set status failed and set an error */
1328 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1330 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1331 _("mail_in_ui_folder_move_target_error"));
1333 /* Notify the queue */
1334 modest_mail_operation_notify_end (self);
1335 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1336 /* Set status failed and set an error */
1337 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1338 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1339 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1340 _("FIXME: parent folder does not accept new folders"));
1342 /* Notify the queue */
1343 modest_mail_operation_notify_end (self);
1345 /* Pick references for async calls */
1346 g_object_ref (folder);
1347 g_object_ref (parent);
1349 /* Move/Copy folder */
1350 tny_folder_copy_async (folder,
1352 tny_folder_get_name (folder),
1355 transfer_folder_status_cb,
1361 modest_mail_operation_rename_folder (ModestMailOperation *self,
1365 ModestMailOperationPrivate *priv;
1366 ModestTnyFolderRules rules;
1368 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1369 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1370 g_return_if_fail (name);
1372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1374 /* Get account and set it into mail_operation */
1375 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1377 /* Check folder rules */
1378 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1379 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1380 /* Set status failed and set an error */
1381 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1382 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1383 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1384 _("FIXME: unable to rename"));
1386 /* Notify about operation end */
1387 modest_mail_operation_notify_end (self);
1389 /* Rename. Camel handles folder subscription/unsubscription */
1390 TnyFolderStore *into;
1392 into = tny_folder_get_folder_store (folder);
1393 tny_folder_copy_async (folder, into, name, TRUE,
1395 transfer_folder_status_cb,
1398 g_object_unref (into);
1403 /* ******************************************************************* */
1404 /* ************************** MSG ACTIONS ************************* */
1405 /* ******************************************************************* */
1407 void modest_mail_operation_get_msg (ModestMailOperation *self,
1409 GetMsgAsyncUserCallback user_callback,
1412 GetMsgAsyncHelper *helper = NULL;
1414 ModestMailOperationPrivate *priv;
1416 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1417 g_return_if_fail (TNY_IS_HEADER (header));
1419 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1420 folder = tny_header_get_folder (header);
1422 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1424 /* Get message from folder */
1426 /* Get account and set it into mail_operation */
1427 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1429 helper = g_slice_new0 (GetMsgAsyncHelper);
1430 helper->mail_op = self;
1431 helper->user_callback = user_callback;
1432 helper->pending_ops = 1;
1433 helper->user_data = user_data;
1435 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1437 g_object_unref (G_OBJECT (folder));
1439 /* Set status failed and set an error */
1440 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1441 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1442 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1443 _("Error trying to get a message. No folder found for header"));
1445 /* Notify the queue */
1446 modest_mail_operation_notify_end (self);
1451 get_msg_cb (TnyFolder *folder,
1457 GetMsgAsyncHelper *helper = NULL;
1458 ModestMailOperation *self = NULL;
1459 ModestMailOperationPrivate *priv = NULL;
1461 helper = (GetMsgAsyncHelper *) user_data;
1462 g_return_if_fail (helper != NULL);
1463 self = helper->mail_op;
1464 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1467 helper->pending_ops--;
1469 /* Check errors and cancel */
1471 priv->error = g_error_copy (*error);
1472 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1476 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1477 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1478 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1479 _("Error trying to refresh the contents of %s"),
1480 tny_folder_get_name (folder));
1484 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1486 /* If user defined callback function was defined, call it */
1487 if (helper->user_callback) {
1488 helper->user_callback (self, NULL, msg, helper->user_data);
1493 if (helper->pending_ops == 0) {
1494 g_slice_free (GetMsgAsyncHelper, helper);
1496 /* Notify about operation end */
1497 modest_mail_operation_notify_end (self);
1502 get_msg_status_cb (GObject *obj,
1506 GetMsgAsyncHelper *helper = NULL;
1507 ModestMailOperation *self;
1508 ModestMailOperationPrivate *priv;
1509 ModestMailOperationState *state;
1511 g_return_if_fail (status != NULL);
1512 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1514 helper = (GetMsgAsyncHelper *) user_data;
1515 g_return_if_fail (helper != NULL);
1517 self = helper->mail_op;
1518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1520 if ((status->position == 1) && (status->of_total == 100))
1526 state = modest_mail_operation_clone_state (self);
1527 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1528 g_slice_free (ModestMailOperationState, state);
1531 /****************************************************/
1533 ModestMailOperation *mail_op;
1535 GetMsgAsyncUserCallback user_callback;
1537 GDestroyNotify notify;
1541 GetMsgAsyncUserCallback user_callback;
1545 ModestMailOperation *mail_op;
1546 } NotifyGetMsgsInfo;
1550 * Used by get_msgs_full_thread to call the user_callback for each
1551 * message that has been read
1554 notify_get_msgs_full (gpointer data)
1556 NotifyGetMsgsInfo *info;
1558 info = (NotifyGetMsgsInfo *) data;
1560 /* Call the user callback */
1561 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1563 g_slice_free (NotifyGetMsgsInfo, info);
1569 * Used by get_msgs_full_thread to free al the thread resources and to
1570 * call the destroy function for the passed user_data
1573 get_msgs_full_destroyer (gpointer data)
1575 GetFullMsgsInfo *info;
1577 info = (GetFullMsgsInfo *) data;
1580 info->notify (info->user_data);
1583 g_object_unref (info->headers);
1584 g_slice_free (GetFullMsgsInfo, info);
1590 get_msgs_full_thread (gpointer thr_user_data)
1592 GetFullMsgsInfo *info;
1593 ModestMailOperationPrivate *priv = NULL;
1594 TnyIterator *iter = NULL;
1596 info = (GetFullMsgsInfo *) thr_user_data;
1597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1599 iter = tny_list_create_iterator (info->headers);
1600 while (!tny_iterator_is_done (iter)) {
1604 header = TNY_HEADER (tny_iterator_get_current (iter));
1605 folder = tny_header_get_folder (header);
1607 /* Get message from folder */
1610 /* The callback will call it per each header */
1611 msg = tny_folder_get_msg (folder, header, &(priv->error));
1614 ModestMailOperationState *state;
1619 /* notify progress */
1620 state = modest_mail_operation_clone_state (info->mail_op);
1621 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1622 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1623 pair, (GDestroyNotify) modest_pair_free);
1625 /* The callback is the responsible for
1626 freeing the message */
1627 if (info->user_callback) {
1628 NotifyGetMsgsInfo *info_notify;
1629 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1630 info_notify->user_callback = info->user_callback;
1631 info_notify->mail_op = info->mail_op;
1632 info_notify->header = g_object_ref (header);
1633 info_notify->msg = g_object_ref (msg);
1634 info_notify->user_data = info->user_data;
1635 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1636 notify_get_msgs_full,
1639 g_object_unref (msg);
1642 /* Set status failed and set an error */
1643 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1644 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1645 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1646 "Error trying to get a message. No folder found for header");
1648 g_object_unref (header);
1649 tny_iterator_next (iter);
1652 /* Set operation status */
1653 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1654 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1656 /* Notify about operation end */
1657 g_idle_add (notify_update_account_queue, info->mail_op);
1659 /* Free thread resources. Will be called after all previous idles */
1660 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1666 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1667 TnyList *header_list,
1668 GetMsgAsyncUserCallback user_callback,
1670 GDestroyNotify notify)
1672 TnyHeader *header = NULL;
1673 TnyFolder *folder = NULL;
1675 ModestMailOperationPrivate *priv = NULL;
1676 GetFullMsgsInfo *info = NULL;
1677 gboolean size_ok = TRUE;
1679 TnyIterator *iter = NULL;
1681 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1683 /* Init mail operation */
1684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1685 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1687 priv->total = tny_list_get_length(header_list);
1689 /* Get account and set it into mail_operation */
1690 if (tny_list_get_length (header_list) >= 1) {
1691 iter = tny_list_create_iterator (header_list);
1692 header = TNY_HEADER (tny_iterator_get_current (iter));
1693 folder = tny_header_get_folder (header);
1694 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1695 g_object_unref (header);
1696 g_object_unref (folder);
1698 if (tny_list_get_length (header_list) == 1) {
1699 g_object_unref (iter);
1704 /* Get msg size limit */
1705 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1706 MODEST_CONF_MSG_SIZE_LIMIT,
1709 g_clear_error (&(priv->error));
1710 max_size = G_MAXINT;
1712 max_size = max_size * KB;
1715 /* Check message size limits. If there is only one message
1716 always retrieve it */
1718 while (!tny_iterator_is_done (iter) && size_ok) {
1719 header = TNY_HEADER (tny_iterator_get_current (iter));
1720 if (tny_header_get_message_size (header) >= max_size)
1722 g_object_unref (header);
1723 tny_iterator_next (iter);
1725 g_object_unref (iter);
1729 /* Create the info */
1730 info = g_slice_new0 (GetFullMsgsInfo);
1731 info->mail_op = self;
1732 info->user_callback = user_callback;
1733 info->user_data = user_data;
1734 info->headers = g_object_ref (header_list);
1735 info->notify = notify;
1737 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1739 /* Set status failed and set an error */
1740 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1741 /* FIXME: the error msg is different for pop */
1742 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1743 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1744 _("emev_ni_ui_imap_msg_size_exceed_error"));
1745 /* Remove from queue and free resources */
1746 modest_mail_operation_notify_end (self);
1754 modest_mail_operation_remove_msg (ModestMailOperation *self,
1756 gboolean remove_to_trash)
1759 ModestMailOperationPrivate *priv;
1761 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1762 g_return_if_fail (TNY_IS_HEADER (header));
1764 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1765 folder = tny_header_get_folder (header);
1767 /* Get account and set it into mail_operation */
1768 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1770 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1772 /* Delete or move to trash */
1773 if (remove_to_trash) {
1774 TnyFolder *trash_folder;
1775 TnyStoreAccount *store_account;
1777 store_account = TNY_STORE_ACCOUNT (modest_tny_folder_get_account (folder));
1778 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1779 TNY_FOLDER_TYPE_TRASH);
1784 headers = tny_simple_list_new ();
1785 tny_list_append (headers, G_OBJECT (header));
1786 g_object_unref (header);
1789 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1790 g_object_unref (headers);
1791 /* g_object_unref (trash_folder); */
1793 ModestMailOperationPrivate *priv;
1795 /* Set status failed and set an error */
1796 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1797 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1798 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1799 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1800 _("Error trying to delete a message. Trash folder not found"));
1803 g_object_unref (G_OBJECT (store_account));
1805 tny_folder_remove_msg (folder, header, &(priv->error));
1807 tny_folder_sync(folder, TRUE, &(priv->error));
1812 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1814 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1817 g_object_unref (G_OBJECT (folder));
1819 /* Notify about operation end */
1820 modest_mail_operation_notify_end (self);
1824 transfer_msgs_status_cb (GObject *obj,
1828 XFerMsgAsyncHelper *helper = NULL;
1829 ModestMailOperation *self;
1830 ModestMailOperationPrivate *priv;
1831 ModestMailOperationState *state;
1834 g_return_if_fail (status != NULL);
1835 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1837 helper = (XFerMsgAsyncHelper *) user_data;
1838 g_return_if_fail (helper != NULL);
1840 self = helper->mail_op;
1841 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1843 if ((status->position == 1) && (status->of_total == 100))
1846 priv->done = status->position;
1847 priv->total = status->of_total;
1849 state = modest_mail_operation_clone_state (self);
1850 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1851 g_slice_free (ModestMailOperationState, state);
1856 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1858 XFerMsgAsyncHelper *helper;
1859 ModestMailOperation *self;
1860 ModestMailOperationPrivate *priv;
1862 helper = (XFerMsgAsyncHelper *) user_data;
1863 self = helper->mail_op;
1865 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1868 priv->error = g_error_copy (*err);
1870 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1871 } else if (cancelled) {
1872 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1873 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1874 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1875 _("Error trying to refresh the contents of %s"),
1876 tny_folder_get_name (folder));
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1882 /* If user defined callback function was defined, call it */
1883 if (helper->user_callback) {
1884 helper->user_callback (priv->source, helper->user_data);
1888 g_object_unref (helper->headers);
1889 g_object_unref (helper->dest_folder);
1890 g_object_unref (helper->mail_op);
1891 g_slice_free (XFerMsgAsyncHelper, helper);
1892 g_object_unref (folder);
1894 /* Notify about operation end */
1895 modest_mail_operation_notify_end (self);
1899 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1902 gboolean delete_original,
1903 XferMsgsAsynUserCallback user_callback,
1906 ModestMailOperationPrivate *priv;
1908 TnyFolder *src_folder;
1909 XFerMsgAsyncHelper *helper;
1911 ModestTnyFolderRules rules;
1913 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1914 g_return_if_fail (TNY_IS_LIST (headers));
1915 g_return_if_fail (TNY_IS_FOLDER (folder));
1917 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1920 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1922 /* Apply folder rules */
1923 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1925 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1926 /* Set status failed and set an error */
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1928 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1929 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1930 _("FIXME: folder does not accept msgs"));
1931 /* Notify the queue */
1932 modest_mail_operation_notify_end (self);
1936 /* Create the helper */
1937 helper = g_slice_new0 (XFerMsgAsyncHelper);
1938 helper->mail_op = g_object_ref(self);
1939 helper->dest_folder = g_object_ref(folder);
1940 helper->headers = g_object_ref(headers);
1941 helper->user_callback = user_callback;
1942 helper->user_data = user_data;
1944 /* Get source folder */
1945 iter = tny_list_create_iterator (headers);
1946 header = TNY_HEADER (tny_iterator_get_current (iter));
1947 src_folder = tny_header_get_folder (header);
1948 g_object_unref (header);
1949 g_object_unref (iter);
1951 /* Get account and set it into mail_operation */
1952 priv->account = modest_tny_folder_get_account (src_folder);
1954 /* Transfer messages */
1955 tny_folder_transfer_msgs_async (src_folder,
1960 transfer_msgs_status_cb,
1966 on_refresh_folder (TnyFolder *folder,
1971 ModestMailOperation *self;
1972 ModestMailOperationPrivate *priv;
1974 self = MODEST_MAIL_OPERATION (user_data);
1975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1978 priv->error = g_error_copy (*error);
1979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1984 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1986 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1987 _("Error trying to refresh the contents of %s"),
1988 tny_folder_get_name (folder));
1992 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1996 g_object_unref (folder);
1998 /* Notify about operation end */
1999 modest_mail_operation_notify_end (self);
2003 on_refresh_folder_status_update (GObject *obj,
2007 ModestMailOperation *self;
2008 ModestMailOperationPrivate *priv;
2009 ModestMailOperationState *state;
2011 g_return_if_fail (status != NULL);
2012 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2014 self = MODEST_MAIL_OPERATION (user_data);
2015 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2017 priv->done = status->position;
2018 priv->total = status->of_total;
2020 state = modest_mail_operation_clone_state (self);
2021 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2022 g_slice_free (ModestMailOperationState, state);
2026 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2029 ModestMailOperationPrivate *priv;
2031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2033 /* Pick a reference */
2034 g_object_ref (folder);
2036 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2038 /* Get account and set it into mail_operation */
2039 priv->account = modest_tny_folder_get_account (folder);
2041 /* Refresh the folder. TODO: tinymail could issue a status
2042 updates before the callback call then this could happen. We
2043 must review the design */
2044 tny_folder_refresh_async (folder,
2046 on_refresh_folder_status_update,
2052 * It's used by the mail operation queue to notify the observers
2053 * attached to that signal that the operation finished. We need to use
2054 * that because tinymail does not give us the progress of a given
2055 * operation when it finishes (it directly calls the operation
2059 modest_mail_operation_notify_end (ModestMailOperation *self)
2061 ModestMailOperationState *state;
2063 /* Notify the observers about the mail opertation end */
2064 state = modest_mail_operation_clone_state (self);
2065 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2066 g_slice_free (ModestMailOperationState, state);