1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-simple-list.h>
38 #include <tny-send-queue.h>
39 #include <tny-status.h>
40 #include <tny-folder-observer.h>
41 #include <camel/camel-stream-mem.h>
42 #include <glib/gi18n.h>
43 #include "modest-platform.h"
44 #include <modest-tny-account.h>
45 #include <modest-tny-send-queue.h>
46 #include <modest-runtime.h>
47 #include "modest-text-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-folder.h"
50 #include "modest-tny-platform-factory.h"
51 #include "modest-marshal.h"
52 #include "modest-error.h"
53 #include "modest-mail-operation.h"
57 /* 'private'/'protected' functions */
58 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
59 static void modest_mail_operation_init (ModestMailOperation *obj);
60 static void modest_mail_operation_finalize (GObject *obj);
62 static void get_msg_cb (TnyFolder *folder,
68 static void get_msg_status_cb (GObject *obj,
72 static void modest_mail_operation_notify_end (ModestMailOperation *self);
74 enum _ModestMailOperationSignals
76 PROGRESS_CHANGED_SIGNAL,
81 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
82 struct _ModestMailOperationPrivate {
88 ErrorCheckingUserCallback error_checking;
89 gpointer error_checking_user_data;
90 ModestMailOperationStatus status;
91 ModestMailOperationTypeOperation op_type;
94 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95 MODEST_TYPE_MAIL_OPERATION, \
96 ModestMailOperationPrivate))
98 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
99 priv->status = new_status;\
102 typedef struct _GetMsgAsyncHelper {
103 ModestMailOperation *mail_op;
104 GetMsgAsyncUserCallback user_callback;
109 typedef struct _XFerMsgAsyncHelper
111 ModestMailOperation *mail_op;
113 TnyFolder *dest_folder;
114 XferMsgsAsynUserCallback user_callback;
116 } XFerMsgAsyncHelper;
119 static GObjectClass *parent_class = NULL;
121 static guint signals[NUM_SIGNALS] = {0};
124 modest_mail_operation_get_type (void)
126 static GType my_type = 0;
128 static const GTypeInfo my_info = {
129 sizeof(ModestMailOperationClass),
130 NULL, /* base init */
131 NULL, /* base finalize */
132 (GClassInitFunc) modest_mail_operation_class_init,
133 NULL, /* class finalize */
134 NULL, /* class data */
135 sizeof(ModestMailOperation),
137 (GInstanceInitFunc) modest_mail_operation_init,
140 my_type = g_type_register_static (G_TYPE_OBJECT,
141 "ModestMailOperation",
148 modest_mail_operation_class_init (ModestMailOperationClass *klass)
150 GObjectClass *gobject_class;
151 gobject_class = (GObjectClass*) klass;
153 parent_class = g_type_class_peek_parent (klass);
154 gobject_class->finalize = modest_mail_operation_finalize;
156 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
159 * ModestMailOperation::progress-changed
160 * @self: the #MailOperation that emits the signal
161 * @user_data: user data set when the signal handler was connected
163 * Emitted when the progress of a mail operation changes
165 signals[PROGRESS_CHANGED_SIGNAL] =
166 g_signal_new ("progress-changed",
167 G_TYPE_FROM_CLASS (gobject_class),
169 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
171 g_cclosure_marshal_VOID__POINTER,
172 G_TYPE_NONE, 1, G_TYPE_POINTER);
176 modest_mail_operation_init (ModestMailOperation *obj)
178 ModestMailOperationPrivate *priv;
180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
182 priv->account = NULL;
183 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
184 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
189 priv->error_checking = NULL;
190 priv->error_checking_user_data = NULL;
194 modest_mail_operation_finalize (GObject *obj)
196 ModestMailOperationPrivate *priv;
198 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
201 g_error_free (priv->error);
205 g_object_unref (priv->source);
209 g_object_unref (priv->account);
210 priv->account = NULL;
214 G_OBJECT_CLASS(parent_class)->finalize (obj);
218 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
221 ModestMailOperation *obj;
222 ModestMailOperationPrivate *priv;
224 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
225 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
227 priv->op_type = op_type;
229 priv->source = g_object_ref(source);
235 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
237 ErrorCheckingUserCallback error_handler,
240 ModestMailOperation *obj;
241 ModestMailOperationPrivate *priv;
243 obj = modest_mail_operation_new (op_type, source);
244 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
246 g_return_val_if_fail (error_handler != NULL, obj);
247 priv->error_checking = error_handler;
253 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
255 ModestMailOperationPrivate *priv;
257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
258 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
260 if (priv->error_checking != NULL)
261 priv->error_checking (self, priv->error_checking_user_data);
265 ModestMailOperationTypeOperation
266 modest_mail_operation_get_type_operation (ModestMailOperation *self)
268 ModestMailOperationPrivate *priv;
270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
272 return priv->op_type;
276 modest_mail_operation_is_mine (ModestMailOperation *self,
279 ModestMailOperationPrivate *priv;
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 if (priv->source == NULL) return FALSE;
284 return priv->source == me;
288 modest_mail_operation_get_source (ModestMailOperation *self)
290 ModestMailOperationPrivate *priv;
292 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 return g_object_ref (priv->source);
297 ModestMailOperationStatus
298 modest_mail_operation_get_status (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
303 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
304 MODEST_MAIL_OPERATION_STATUS_INVALID);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
311 modest_mail_operation_get_error (ModestMailOperation *self)
313 ModestMailOperationPrivate *priv;
315 g_return_val_if_fail (self, NULL);
316 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
323 modest_mail_operation_cancel (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 if (!MODEST_IS_MAIL_OPERATION (self)) {
328 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
334 /* cancel current operation in account */
335 tny_account_cancel (priv->account);
338 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
340 /* Notify about operation end */
341 modest_mail_operation_notify_end (self);
347 modest_mail_operation_get_task_done (ModestMailOperation *self)
349 ModestMailOperationPrivate *priv;
351 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
358 modest_mail_operation_get_task_total (ModestMailOperation *self)
360 ModestMailOperationPrivate *priv;
362 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
369 modest_mail_operation_is_finished (ModestMailOperation *self)
371 ModestMailOperationPrivate *priv;
372 gboolean retval = FALSE;
374 if (!MODEST_IS_MAIL_OPERATION (self)) {
375 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
382 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
384 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
394 modest_mail_operation_get_id (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
405 modest_mail_operation_set_id (ModestMailOperation *self,
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 * Creates an image of the current state of a mail operation, the
418 * caller must free it
420 static ModestMailOperationState *
421 modest_mail_operation_clone_state (ModestMailOperation *self)
423 ModestMailOperationState *state;
424 ModestMailOperationPrivate *priv;
426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
428 state = g_slice_new (ModestMailOperationState);
430 state->status = priv->status;
431 state->op_type = priv->op_type;
432 state->done = priv->done;
433 state->total = priv->total;
434 state->finished = modest_mail_operation_is_finished (self);
439 /* ******************************************************************* */
440 /* ************************** SEND ACTIONS ************************* */
441 /* ******************************************************************* */
444 modest_mail_operation_send_mail (ModestMailOperation *self,
445 TnyTransportAccount *transport_account,
448 TnySendQueue *send_queue = NULL;
449 ModestMailOperationPrivate *priv;
451 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
452 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
453 g_return_if_fail (TNY_IS_MSG (msg));
455 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
457 /* Get account and set it into mail_operation */
458 priv->account = g_object_ref (transport_account);
460 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
461 if (!TNY_IS_SEND_QUEUE(send_queue)) {
462 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
463 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
464 "modest: could not find send queue for account\n");
466 tny_send_queue_add (send_queue, msg, &(priv->error));
469 /* Notify about operation end */
470 modest_mail_operation_notify_end (self);
474 modest_mail_operation_send_new_mail (ModestMailOperation *self,
475 TnyTransportAccount *transport_account,
476 const gchar *from, const gchar *to,
477 const gchar *cc, const gchar *bcc,
478 const gchar *subject, const gchar *plain_body,
479 const gchar *html_body,
480 const GList *attachments_list,
481 TnyHeaderFlags priority_flags)
483 TnyMsg *new_msg = NULL;
484 ModestMailOperationPrivate *priv = NULL;
486 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
487 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
491 /* Get account and set it into mail_operation */
492 priv->account = g_object_ref (transport_account);
494 /* Check parametters */
496 /* Set status failed and set an error */
497 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
498 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
499 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
500 _("Error trying to send a mail. You need to set at least one recipient"));
504 if (html_body == NULL) {
505 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
507 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
510 g_printerr ("modest: failed to create a new msg\n");
514 /* TODO: add priority handling. It's received in the priority_flags operator, and
515 it should have effect in the sending operation */
517 /* Call mail operation */
518 modest_mail_operation_send_mail (self, transport_account, new_msg);
521 g_object_unref (G_OBJECT (new_msg));
525 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
526 TnyTransportAccount *transport_account,
527 const gchar *from, const gchar *to,
528 const gchar *cc, const gchar *bcc,
529 const gchar *subject, const gchar *plain_body,
530 const gchar *html_body,
531 const GList *attachments_list,
532 TnyHeaderFlags priority_flags)
535 TnyFolder *folder = NULL;
536 ModestMailOperationPrivate *priv = NULL;
538 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
539 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
541 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
543 /* Get account and set it into mail_operation */
544 priv->account = g_object_ref (transport_account);
546 if (html_body == NULL) {
547 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
549 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
552 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
553 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
554 "modest: failed to create a new msg\n");
558 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
561 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
562 "modest: failed to create a new msg\n");
566 tny_folder_add_msg (folder, msg, &(priv->error));
572 g_object_unref (G_OBJECT(msg));
574 g_object_unref (G_OBJECT(folder));
576 modest_mail_operation_notify_end (self);
581 ModestMailOperation *mail_op;
582 TnyStoreAccount *account;
583 TnyTransportAccount *transport_account;
586 gchar *retrieve_type;
589 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
590 /* We use this folder observer to track the headers that have been
591 * added to a folder */
594 TnyList *new_headers;
595 } InternalFolderObserver;
599 } InternalFolderObserverClass;
601 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
603 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
604 internal_folder_observer,
606 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
610 foreach_add_item (gpointer header, gpointer user_data)
612 /* printf("DEBUG: %s: header subject=%s\n",
613 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
615 tny_list_prepend (TNY_LIST (user_data),
616 g_object_ref (G_OBJECT (header)));
619 /* This is the method that looks for new messages in a folder */
621 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
623 InternalFolderObserver *derived = (InternalFolderObserver *)self;
625 TnyFolderChangeChanged changed;
627 changed = tny_folder_change_get_changed (change);
629 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
632 /* Get added headers */
633 list = tny_simple_list_new ();
634 tny_folder_change_get_added_headers (change, list);
636 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
637 * __FUNCTION__, tny_list_get_length(list));
640 /* Add them to the folder observer */
641 tny_list_foreach (list, foreach_add_item,
642 derived->new_headers);
644 g_object_unref (G_OBJECT (list));
649 internal_folder_observer_init (InternalFolderObserver *self)
651 self->new_headers = tny_simple_list_new ();
654 internal_folder_observer_finalize (GObject *object)
656 InternalFolderObserver *self;
658 self = (InternalFolderObserver *) object;
659 g_object_unref (self->new_headers);
661 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
664 tny_folder_observer_init (TnyFolderObserverIface *iface)
666 iface->update_func = internal_folder_observer_update;
669 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
671 GObjectClass *object_class;
673 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
674 object_class = (GObjectClass*) klass;
675 object_class->finalize = internal_folder_observer_finalize;
681 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
684 TnyList *folders = tny_simple_list_new ();
686 tny_folder_store_get_folders (store, folders, query, NULL);
687 iter = tny_list_create_iterator (folders);
689 while (!tny_iterator_is_done (iter)) {
691 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
693 tny_list_prepend (all_folders, G_OBJECT (folder));
694 recurse_folders (folder, query, all_folders);
695 g_object_unref (G_OBJECT (folder));
697 tny_iterator_next (iter);
699 g_object_unref (G_OBJECT (iter));
700 g_object_unref (G_OBJECT (folders));
704 * Issues the "progress-changed" signal. The timer won't be removed,
705 * so you must call g_source_remove to stop the signal emission
708 idle_notify_progress (gpointer data)
710 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
711 ModestMailOperationState *state;
713 state = modest_mail_operation_clone_state (mail_op);
714 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
715 g_slice_free (ModestMailOperationState, state);
721 * Issues the "progress-changed" signal and removes the timer. It uses
722 * a lock to ensure that the progress information of the mail
723 * operation is not modified while there are notifications pending
726 idle_notify_progress_once (gpointer data)
730 pair = (ModestPair *) data;
732 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
734 /* Free the state and the reference to the mail operation */
735 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
736 g_object_unref (pair->first);
742 * Used by update_account_thread to notify the queue from the main
743 * loop. We call it inside an idle call to achieve that
746 notify_update_account_queue (gpointer data)
748 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
750 modest_mail_operation_notify_end (mail_op);
751 g_object_unref (mail_op);
757 compare_headers_by_date (gconstpointer a,
760 TnyHeader **header1, **header2;
763 header1 = (TnyHeader **) a;
764 header2 = (TnyHeader **) b;
766 sent1 = tny_header_get_date_sent (*header1);
767 sent2 = tny_header_get_date_sent (*header2);
769 /* We want the most recent ones (greater time_t) at the
778 update_account_thread (gpointer thr_user_data)
780 UpdateAccountInfo *info;
781 TnyList *all_folders = NULL;
782 GPtrArray *new_headers;
783 TnyIterator *iter = NULL;
784 TnyFolderStoreQuery *query = NULL;
785 ModestMailOperationPrivate *priv;
786 ModestTnySendQueue *send_queue;
788 info = (UpdateAccountInfo *) thr_user_data;
789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
791 /* Get account and set it into mail_operation */
792 priv->account = g_object_ref (info->account);
794 /* Get all the folders. We can do it synchronously because
795 we're already running in a different thread than the UI */
796 all_folders = tny_simple_list_new ();
797 query = tny_folder_store_query_new ();
798 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
799 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
804 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
808 iter = tny_list_create_iterator (all_folders);
809 while (!tny_iterator_is_done (iter)) {
810 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
812 recurse_folders (folder, query, all_folders);
813 tny_iterator_next (iter);
815 g_object_unref (G_OBJECT (iter));
817 /* Update status and notify. We need to call the notification
818 with a source function in order to call it from the main
819 loop. We need that in order not to get into trouble with
820 Gtk+. We use a timeout in order to provide more status
821 information, because the sync tinymail call does not
822 provide it for the moment */
823 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
825 /* Refresh folders */
826 new_headers = g_ptr_array_new ();
827 iter = tny_list_create_iterator (all_folders);
828 while (!tny_iterator_is_done (iter) && !priv->error) {
830 InternalFolderObserver *observer;
831 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
833 /* Refresh the folder */
834 /* Our observer receives notification of new emails during folder refreshes,
835 * so we can use observer->new_headers.
836 * TODO: This does not seem to be providing accurate numbers.
837 * Possibly the observer is notified asynchronously.
839 observer = g_object_new (internal_folder_observer_get_type (), NULL);
840 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
842 /* This gets the status information (headers) from the server.
843 * We use the blocking version, because we are already in a separate
846 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
848 /* If the retrieve type is headers only do nothing more */
849 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
850 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
853 iter = tny_list_create_iterator (observer->new_headers);
854 while (!tny_iterator_is_done (iter)) {
855 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
856 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
857 * __FUNCTION__, tny_account_get_id (priv->account),
858 * tny_header_get_subject (header));
861 /* Apply per-message size limits */
862 if (tny_header_get_message_size (header) < info->max_size)
863 g_ptr_array_add (new_headers, g_object_ref (header));
865 g_object_unref (header);
866 tny_iterator_next (iter);
868 g_object_unref (iter);
871 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
872 g_object_unref (observer);
876 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
878 g_object_unref (G_OBJECT (folder));
879 tny_iterator_next (iter);
881 g_object_unref (G_OBJECT (iter));
882 g_source_remove (timeout);
884 if (new_headers->len > 0) {
888 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
890 /* Apply message count limit */
891 /* If the number of messages exceeds the maximum, ask the
892 * user to download them all,
893 * as per the UI spec "Retrieval Limits" section in 4.4:
895 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
896 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
897 if (new_headers->len > info->retrieve_limit) {
898 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
899 * with 'Get all' and 'Newest only' buttons. */
900 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
901 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
902 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
903 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
904 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
909 priv->total = MIN (new_headers->len, info->retrieve_limit);
910 while (msg_num < priv->total) {
912 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
913 TnyFolder *folder = tny_header_get_folder (header);
914 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
915 ModestMailOperationState *state;
919 /* We can not just use the mail operation because the
920 values of done and total could change before the
922 state = modest_mail_operation_clone_state (info->mail_op);
923 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
924 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
925 pair, (GDestroyNotify) modest_pair_free);
927 g_object_unref (msg);
928 g_object_unref (folder);
932 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
933 g_ptr_array_free (new_headers, FALSE);
937 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
940 if (priv->account != NULL)
941 g_object_unref (priv->account);
942 priv->account = g_object_ref (info->transport_account);
944 send_queue = modest_runtime_get_send_queue (info->transport_account);
946 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
947 modest_tny_send_queue_try_to_send (send_queue);
948 g_source_remove (timeout);
950 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
951 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
952 "cannot create a send queue for %s\n",
953 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
957 /* Check if the operation was a success */
959 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
961 /* Update the last updated key */
962 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
963 tny_account_get_id (TNY_ACCOUNT (info->account)),
964 MODEST_ACCOUNT_LAST_UPDATED,
970 /* Notify about operation end. Note that the info could be
971 freed before this idle happens, but the mail operation will
973 g_idle_add (notify_update_account_queue, info->mail_op);
976 g_object_unref (query);
977 g_object_unref (all_folders);
978 g_object_unref (info->account);
979 g_object_unref (info->transport_account);
980 g_free (info->retrieve_type);
981 g_slice_free (UpdateAccountInfo, info);
987 modest_mail_operation_update_account (ModestMailOperation *self,
988 const gchar *account_name)
991 UpdateAccountInfo *info;
992 ModestMailOperationPrivate *priv;
993 ModestAccountMgr *mgr;
994 TnyStoreAccount *modest_account;
995 TnyTransportAccount *transport_account;
997 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
998 g_return_val_if_fail (account_name, FALSE);
1000 /* Make sure that we have a connection, and request one
1002 * TODO: Is there some way to trigger this for every attempt to
1003 * use the network? */
1004 if (!modest_platform_connect_and_wait(NULL))
1007 /* Init mail operation. Set total and done to 0, and do not
1008 update them, this way the progress objects will know that
1009 we have no clue about the number of the objects */
1010 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1013 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1015 /* Get the Modest account */
1016 modest_account = (TnyStoreAccount *)
1017 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
1019 TNY_ACCOUNT_TYPE_STORE);
1021 if (!modest_account) {
1022 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1023 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1024 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1025 "cannot get tny store account for %s\n", account_name);
1026 modest_mail_operation_notify_end (self);
1030 /* Get the transport account, we can not do it in the thread
1031 due to some problems with dbus */
1032 transport_account = (TnyTransportAccount *)
1033 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1035 if (!transport_account) {
1036 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1037 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1038 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1039 "cannot get tny transport account for %s\n", account_name);
1040 modest_mail_operation_notify_end (self);
1044 /* Create the helper object */
1045 info = g_slice_new (UpdateAccountInfo);
1046 info->mail_op = self;
1047 info->account = modest_account;
1048 info->transport_account = transport_account;
1050 /* Get the message size limit */
1051 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1052 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1053 if (info->max_size == 0)
1054 info->max_size = G_MAXINT;
1056 info->max_size = info->max_size * KB;
1058 /* Get per-account retrieval type */
1059 mgr = modest_runtime_get_account_mgr ();
1060 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1061 MODEST_ACCOUNT_RETRIEVE, FALSE);
1063 /* Get per-account message amount retrieval limit */
1064 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1065 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1066 if (info->retrieve_limit == 0)
1067 info->retrieve_limit = G_MAXINT;
1069 printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit);
1071 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1076 /* ******************************************************************* */
1077 /* ************************** STORE ACTIONS ************************* */
1078 /* ******************************************************************* */
1082 modest_mail_operation_create_folder (ModestMailOperation *self,
1083 TnyFolderStore *parent,
1086 ModestMailOperationPrivate *priv;
1087 TnyFolder *new_folder = NULL;
1089 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1090 g_return_val_if_fail (name, NULL);
1092 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1095 if (TNY_IS_FOLDER (parent)) {
1096 /* Check folder rules */
1097 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1098 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1099 /* Set status failed and set an error */
1100 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1101 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1102 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1103 _("mail_in_ui_folder_create_error"));
1108 /* Create the folder */
1109 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1110 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1112 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1115 /* Notify about operation end */
1116 modest_mail_operation_notify_end (self);
1122 modest_mail_operation_remove_folder (ModestMailOperation *self,
1124 gboolean remove_to_trash)
1126 TnyAccount *account;
1127 ModestMailOperationPrivate *priv;
1128 ModestTnyFolderRules rules;
1130 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1131 g_return_if_fail (TNY_IS_FOLDER (folder));
1133 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1135 /* Check folder rules */
1136 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1137 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1138 /* Set status failed and set an error */
1139 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1140 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1141 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1142 _("mail_in_ui_folder_delete_error"));
1146 /* Get the account */
1147 account = tny_folder_get_account (folder);
1148 priv->account = g_object_ref(account);
1150 /* Delete folder or move to trash */
1151 if (remove_to_trash) {
1152 TnyFolder *trash_folder = NULL;
1153 trash_folder = modest_tny_account_get_special_folder (account,
1154 TNY_FOLDER_TYPE_TRASH);
1155 /* TODO: error_handling */
1156 modest_mail_operation_xfer_folder (self, folder,
1157 TNY_FOLDER_STORE (trash_folder), TRUE);
1159 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1161 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1162 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1165 g_object_unref (G_OBJECT (parent));
1167 g_object_unref (G_OBJECT (account));
1170 /* Notify about operation end */
1171 modest_mail_operation_notify_end (self);
1175 transfer_folder_status_cb (GObject *obj,
1179 ModestMailOperation *self;
1180 ModestMailOperationPrivate *priv;
1181 ModestMailOperationState *state;
1183 g_return_if_fail (status != NULL);
1184 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1186 self = MODEST_MAIL_OPERATION (user_data);
1187 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1189 if ((status->position == 1) && (status->of_total == 100))
1192 priv->done = status->position;
1193 priv->total = status->of_total;
1195 state = modest_mail_operation_clone_state (self);
1196 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1197 g_slice_free (ModestMailOperationState, state);
1202 transfer_folder_cb (TnyFolder *folder,
1203 TnyFolderStore *into,
1205 TnyFolder *new_folder, GError **err,
1208 ModestMailOperation *self = NULL;
1209 ModestMailOperationPrivate *priv = NULL;
1211 self = MODEST_MAIL_OPERATION (user_data);
1213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1216 priv->error = g_error_copy (*err);
1218 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1219 } else if (cancelled) {
1220 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1221 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1222 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1223 _("Transference of %s was cancelled."),
1224 tny_folder_get_name (folder));
1227 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1231 g_object_unref (folder);
1232 g_object_unref (into);
1233 if (new_folder != NULL)
1234 g_object_unref (new_folder);
1236 /* Notify about operation end */
1237 modest_mail_operation_notify_end (self);
1241 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1243 TnyFolderStore *parent,
1244 gboolean delete_original)
1246 ModestMailOperationPrivate *priv = NULL;
1247 ModestTnyFolderRules parent_rules, rules;
1249 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1250 g_return_if_fail (TNY_IS_FOLDER (folder));
1251 g_return_if_fail (TNY_IS_FOLDER (parent));
1253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1255 /* Get account and set it into mail_operation */
1256 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1257 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1259 /* Get folder rules */
1260 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1261 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1263 if (!TNY_IS_FOLDER_STORE (parent)) {
1267 /* The moveable restriction is applied also to copy operation */
1268 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1269 /* Set status failed and set an error */
1270 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1271 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1272 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1273 _("mail_in_ui_folder_move_target_error"));
1275 /* Notify the queue */
1276 modest_mail_operation_notify_end (self);
1277 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1278 /* Set status failed and set an error */
1279 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1280 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1281 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1282 _("FIXME: parent folder does not accept new folders"));
1284 /* Notify the queue */
1285 modest_mail_operation_notify_end (self);
1287 /* Pick references for async calls */
1288 g_object_ref (folder);
1289 g_object_ref (parent);
1291 /* Move/Copy folder */
1292 tny_folder_copy_async (folder,
1294 tny_folder_get_name (folder),
1297 transfer_folder_status_cb,
1303 modest_mail_operation_rename_folder (ModestMailOperation *self,
1307 ModestMailOperationPrivate *priv;
1308 ModestTnyFolderRules rules;
1310 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1311 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1312 g_return_if_fail (name);
1314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1316 /* Get account and set it into mail_operation */
1317 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1319 /* Check folder rules */
1320 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1321 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1322 /* Set status failed and set an error */
1323 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1324 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1325 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1326 _("FIXME: unable to rename"));
1328 /* Notify about operation end */
1329 modest_mail_operation_notify_end (self);
1331 /* Rename. Camel handles folder subscription/unsubscription */
1332 TnyFolderStore *into;
1334 into = tny_folder_get_folder_store (folder);
1335 tny_folder_copy_async (folder, into, name, TRUE,
1337 transfer_folder_status_cb,
1340 g_object_unref (into);
1345 /* ******************************************************************* */
1346 /* ************************** MSG ACTIONS ************************* */
1347 /* ******************************************************************* */
1349 void modest_mail_operation_get_msg (ModestMailOperation *self,
1351 GetMsgAsyncUserCallback user_callback,
1354 GetMsgAsyncHelper *helper = NULL;
1356 ModestMailOperationPrivate *priv;
1358 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1359 g_return_if_fail (TNY_IS_HEADER (header));
1361 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1362 folder = tny_header_get_folder (header);
1364 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1366 /* Get message from folder */
1368 /* Get account and set it into mail_operation */
1369 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1371 helper = g_slice_new0 (GetMsgAsyncHelper);
1372 helper->mail_op = self;
1373 helper->user_callback = user_callback;
1374 helper->pending_ops = 1;
1375 helper->user_data = user_data;
1377 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1379 g_object_unref (G_OBJECT (folder));
1381 /* Set status failed and set an error */
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1383 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1384 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1385 _("Error trying to get a message. No folder found for header"));
1387 /* Notify the queue */
1388 modest_mail_operation_notify_end (self);
1393 get_msg_cb (TnyFolder *folder,
1399 GetMsgAsyncHelper *helper = NULL;
1400 ModestMailOperation *self = NULL;
1401 ModestMailOperationPrivate *priv = NULL;
1403 helper = (GetMsgAsyncHelper *) user_data;
1404 g_return_if_fail (helper != NULL);
1405 self = helper->mail_op;
1406 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1409 helper->pending_ops--;
1411 /* Check errors and cancel */
1413 priv->error = g_error_copy (*error);
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1418 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1419 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1420 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1421 _("Error trying to refresh the contents of %s"),
1422 tny_folder_get_name (folder));
1426 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1428 /* If user defined callback function was defined, call it */
1429 if (helper->user_callback) {
1430 helper->user_callback (self, NULL, msg, helper->user_data);
1435 if (helper->pending_ops == 0) {
1436 g_slice_free (GetMsgAsyncHelper, helper);
1438 /* Notify about operation end */
1439 modest_mail_operation_notify_end (self);
1444 get_msg_status_cb (GObject *obj,
1448 GetMsgAsyncHelper *helper = NULL;
1449 ModestMailOperation *self;
1450 ModestMailOperationPrivate *priv;
1451 ModestMailOperationState *state;
1453 g_return_if_fail (status != NULL);
1454 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1456 helper = (GetMsgAsyncHelper *) user_data;
1457 g_return_if_fail (helper != NULL);
1459 self = helper->mail_op;
1460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1462 if ((status->position == 1) && (status->of_total == 100))
1468 state = modest_mail_operation_clone_state (self);
1469 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1470 g_slice_free (ModestMailOperationState, state);
1473 /****************************************************/
1475 ModestMailOperation *mail_op;
1477 GetMsgAsyncUserCallback user_callback;
1479 GDestroyNotify notify;
1483 GetMsgAsyncUserCallback user_callback;
1487 ModestMailOperation *mail_op;
1488 } NotifyGetMsgsInfo;
1492 * Used by get_msgs_full_thread to call the user_callback for each
1493 * message that has been read
1496 notify_get_msgs_full (gpointer data)
1498 NotifyGetMsgsInfo *info;
1500 info = (NotifyGetMsgsInfo *) data;
1502 /* Call the user callback */
1503 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1505 g_slice_free (NotifyGetMsgsInfo, info);
1511 * Used by get_msgs_full_thread to free al the thread resources and to
1512 * call the destroy function for the passed user_data
1515 get_msgs_full_destroyer (gpointer data)
1517 GetFullMsgsInfo *info;
1519 info = (GetFullMsgsInfo *) data;
1522 info->notify (info->user_data);
1525 g_object_unref (info->headers);
1526 g_slice_free (GetFullMsgsInfo, info);
1532 get_msgs_full_thread (gpointer thr_user_data)
1534 GetFullMsgsInfo *info;
1535 ModestMailOperationPrivate *priv = NULL;
1536 TnyIterator *iter = NULL;
1538 info = (GetFullMsgsInfo *) thr_user_data;
1539 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1541 iter = tny_list_create_iterator (info->headers);
1542 while (!tny_iterator_is_done (iter)) {
1546 header = TNY_HEADER (tny_iterator_get_current (iter));
1547 folder = tny_header_get_folder (header);
1549 /* Get message from folder */
1552 /* The callback will call it per each header */
1553 msg = tny_folder_get_msg (folder, header, &(priv->error));
1556 ModestMailOperationState *state;
1561 /* notify progress */
1562 state = modest_mail_operation_clone_state (info->mail_op);
1563 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1564 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1565 pair, (GDestroyNotify) modest_pair_free);
1567 /* The callback is the responsible for
1568 freeing the message */
1569 if (info->user_callback) {
1570 NotifyGetMsgsInfo *info_notify;
1571 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1572 info_notify->user_callback = info->user_callback;
1573 info_notify->mail_op = info->mail_op;
1574 info_notify->header = g_object_ref (header);
1575 info_notify->msg = g_object_ref (msg);
1576 info_notify->user_data = info->user_data;
1577 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1578 notify_get_msgs_full,
1581 g_object_unref (msg);
1584 /* Set status failed and set an error */
1585 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1586 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1587 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1588 "Error trying to get a message. No folder found for header");
1590 g_object_unref (header);
1591 tny_iterator_next (iter);
1594 /* Set operation status */
1595 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1596 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1598 /* Notify about operation end */
1599 g_idle_add (notify_update_account_queue, info->mail_op);
1601 /* Free thread resources. Will be called after all previous idles */
1602 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1608 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1609 TnyList *header_list,
1610 GetMsgAsyncUserCallback user_callback,
1612 GDestroyNotify notify)
1614 TnyHeader *header = NULL;
1615 TnyFolder *folder = NULL;
1617 ModestMailOperationPrivate *priv = NULL;
1618 GetFullMsgsInfo *info = NULL;
1619 gboolean size_ok = TRUE;
1621 TnyIterator *iter = NULL;
1623 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1625 /* Init mail operation */
1626 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1627 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1629 priv->total = tny_list_get_length(header_list);
1631 /* Get account and set it into mail_operation */
1632 if (tny_list_get_length (header_list) > 1) {
1633 iter = tny_list_create_iterator (header_list);
1634 header = TNY_HEADER (tny_iterator_get_current (iter));
1635 folder = tny_header_get_folder (header);
1636 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1637 g_object_unref (header);
1638 g_object_unref (folder);
1641 /* Get msg size limit */
1642 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1643 MODEST_CONF_MSG_SIZE_LIMIT,
1646 g_clear_error (&(priv->error));
1647 max_size = G_MAXINT;
1649 max_size = max_size * KB;
1652 /* Check message size limits. If there is only one message
1653 always retrieve it */
1655 while (!tny_iterator_is_done (iter) && size_ok) {
1656 header = TNY_HEADER (tny_iterator_get_current (iter));
1657 if (tny_header_get_message_size (header) >= max_size)
1659 g_object_unref (header);
1660 tny_iterator_next (iter);
1662 g_object_unref (iter);
1666 /* Create the info */
1667 info = g_slice_new0 (GetFullMsgsInfo);
1668 info->mail_op = self;
1669 info->user_callback = user_callback;
1670 info->user_data = user_data;
1671 info->headers = g_object_ref (header_list);
1672 info->notify = notify;
1674 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1676 /* Set status failed and set an error */
1677 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1678 /* FIXME: the error msg is different for pop */
1679 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1680 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1681 _("emev_ni_ui_imap_msg_size_exceed_error"));
1682 /* Remove from queue and free resources */
1683 modest_mail_operation_notify_end (self);
1691 modest_mail_operation_remove_msg (ModestMailOperation *self,
1693 gboolean remove_to_trash)
1696 ModestMailOperationPrivate *priv;
1698 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1699 g_return_if_fail (TNY_IS_HEADER (header));
1701 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1702 folder = tny_header_get_folder (header);
1704 /* Get account and set it into mail_operation */
1705 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1707 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1709 /* Delete or move to trash */
1710 if (remove_to_trash) {
1711 TnyFolder *trash_folder;
1712 TnyStoreAccount *store_account;
1714 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1715 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1716 TNY_FOLDER_TYPE_TRASH);
1721 headers = tny_simple_list_new ();
1722 tny_list_append (headers, G_OBJECT (header));
1723 g_object_unref (header);
1726 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1727 g_object_unref (headers);
1728 /* g_object_unref (trash_folder); */
1730 ModestMailOperationPrivate *priv;
1732 /* Set status failed and set an error */
1733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1734 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1735 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1736 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1737 _("Error trying to delete a message. Trash folder not found"));
1740 g_object_unref (G_OBJECT (store_account));
1742 tny_folder_remove_msg (folder, header, &(priv->error));
1744 tny_folder_sync(folder, TRUE, &(priv->error));
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1754 g_object_unref (G_OBJECT (folder));
1756 /* Notify about operation end */
1757 modest_mail_operation_notify_end (self);
1761 transfer_msgs_status_cb (GObject *obj,
1765 XFerMsgAsyncHelper *helper = NULL;
1766 ModestMailOperation *self;
1767 ModestMailOperationPrivate *priv;
1768 ModestMailOperationState *state;
1771 g_return_if_fail (status != NULL);
1772 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1774 helper = (XFerMsgAsyncHelper *) user_data;
1775 g_return_if_fail (helper != NULL);
1777 self = helper->mail_op;
1778 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1780 if ((status->position == 1) && (status->of_total == 100))
1783 priv->done = status->position;
1784 priv->total = status->of_total;
1786 state = modest_mail_operation_clone_state (self);
1787 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1788 g_slice_free (ModestMailOperationState, state);
1793 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1795 XFerMsgAsyncHelper *helper;
1796 ModestMailOperation *self;
1797 ModestMailOperationPrivate *priv;
1799 helper = (XFerMsgAsyncHelper *) user_data;
1800 self = helper->mail_op;
1802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1805 priv->error = g_error_copy (*err);
1807 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1808 } else if (cancelled) {
1809 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1810 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1811 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1812 _("Error trying to refresh the contents of %s"),
1813 tny_folder_get_name (folder));
1816 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1819 /* If user defined callback function was defined, call it */
1820 if (helper->user_callback) {
1821 helper->user_callback (priv->source, helper->user_data);
1825 g_object_unref (helper->headers);
1826 g_object_unref (helper->dest_folder);
1827 g_object_unref (helper->mail_op);
1828 g_slice_free (XFerMsgAsyncHelper, helper);
1829 g_object_unref (folder);
1831 /* Notify about operation end */
1832 modest_mail_operation_notify_end (self);
1836 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1839 gboolean delete_original,
1840 XferMsgsAsynUserCallback user_callback,
1843 ModestMailOperationPrivate *priv;
1845 TnyFolder *src_folder;
1846 XFerMsgAsyncHelper *helper;
1848 ModestTnyFolderRules rules;
1850 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1851 g_return_if_fail (TNY_IS_LIST (headers));
1852 g_return_if_fail (TNY_IS_FOLDER (folder));
1854 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1859 /* Apply folder rules */
1860 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1862 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1863 /* Set status failed and set an error */
1864 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1865 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1866 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1867 _("FIXME: folder does not accept msgs"));
1868 /* Notify the queue */
1869 modest_mail_operation_notify_end (self);
1873 /* Create the helper */
1874 helper = g_slice_new0 (XFerMsgAsyncHelper);
1875 helper->mail_op = g_object_ref(self);
1876 helper->dest_folder = g_object_ref(folder);
1877 helper->headers = g_object_ref(headers);
1878 helper->user_callback = user_callback;
1879 helper->user_data = user_data;
1881 /* Get source folder */
1882 iter = tny_list_create_iterator (headers);
1883 header = TNY_HEADER (tny_iterator_get_current (iter));
1884 src_folder = tny_header_get_folder (header);
1885 g_object_unref (header);
1886 g_object_unref (iter);
1888 /* Get account and set it into mail_operation */
1889 priv->account = tny_folder_get_account (src_folder);
1891 /* Transfer messages */
1892 tny_folder_transfer_msgs_async (src_folder,
1897 transfer_msgs_status_cb,
1903 on_refresh_folder (TnyFolder *folder,
1908 ModestMailOperation *self;
1909 ModestMailOperationPrivate *priv;
1911 self = MODEST_MAIL_OPERATION (user_data);
1912 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1915 priv->error = g_error_copy (*error);
1916 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1924 _("Error trying to refresh the contents of %s"),
1925 tny_folder_get_name (folder));
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1933 g_object_unref (folder);
1935 /* Notify about operation end */
1936 modest_mail_operation_notify_end (self);
1940 on_refresh_folder_status_update (GObject *obj,
1944 ModestMailOperation *self;
1945 ModestMailOperationPrivate *priv;
1946 ModestMailOperationState *state;
1948 g_return_if_fail (status != NULL);
1949 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1951 self = MODEST_MAIL_OPERATION (user_data);
1952 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1954 priv->done = status->position;
1955 priv->total = status->of_total;
1957 state = modest_mail_operation_clone_state (self);
1958 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1959 g_slice_free (ModestMailOperationState, state);
1963 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1966 ModestMailOperationPrivate *priv;
1968 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1970 /* Pick a reference */
1971 g_object_ref (folder);
1973 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1975 /* Get account and set it into mail_operation */
1976 priv->account = tny_folder_get_account (folder);
1978 /* Refresh the folder. TODO: tinymail could issue a status
1979 updates before the callback call then this could happen. We
1980 must review the design */
1981 tny_folder_refresh_async (folder,
1983 on_refresh_folder_status_update,
1989 * It's used by the mail operation queue to notify the observers
1990 * attached to that signal that the operation finished. We need to use
1991 * that because tinymail does not give us the progress of a given
1992 * operation when it finishes (it directly calls the operation
1996 modest_mail_operation_notify_end (ModestMailOperation *self)
1998 ModestMailOperationState *state;
2000 /* Notify the observers about the mail opertation end */
2001 state = modest_mail_operation_clone_state (self);
2002 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2003 g_slice_free (ModestMailOperationState, state);
2005 /* Notify the queue */
2006 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);