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,
477 const gchar *from, const gchar *to,
478 const gchar *cc, const gchar *bcc,
479 const gchar *subject, const gchar *plain_body,
480 const gchar *html_body,
481 const GList *attachments_list,
482 TnyHeaderFlags priority_flags)
484 TnyMsg *new_msg = NULL;
485 TnyFolder *folder = NULL;
486 ModestMailOperationPrivate *priv = NULL;
488 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
489 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
493 /* Get account and set it into mail_operation */
494 priv->account = g_object_ref (transport_account);
496 /* Check parametters */
498 /* Set status failed and set an error */
499 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
500 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
501 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
502 _("Error trying to send a mail. You need to set at least one recipient"));
506 if (html_body == NULL) {
507 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
509 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
512 g_printerr ("modest: failed to create a new msg\n");
516 /* TODO: add priority handling. It's received in the priority_flags operator, and
517 it should have effect in the sending operation */
519 /* Call mail operation */
520 modest_mail_operation_send_mail (self, transport_account, new_msg);
522 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
524 if (draft_msg != NULL) {
525 TnyHeader *header = tny_msg_get_header (draft_msg);
526 tny_folder_remove_msg (folder, header, NULL);
527 g_object_unref (header);
532 g_object_unref (G_OBJECT (new_msg));
536 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
537 TnyTransportAccount *transport_account,
539 const gchar *from, const gchar *to,
540 const gchar *cc, const gchar *bcc,
541 const gchar *subject, const gchar *plain_body,
542 const gchar *html_body,
543 const GList *attachments_list,
544 TnyHeaderFlags priority_flags)
547 TnyFolder *folder = NULL;
548 ModestMailOperationPrivate *priv = NULL;
550 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
551 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
553 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
555 /* Get account and set it into mail_operation */
556 priv->account = g_object_ref (transport_account);
558 if (html_body == NULL) {
559 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
561 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
564 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
565 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
566 "modest: failed to create a new msg\n");
570 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
572 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
573 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
574 "modest: failed to create a new msg\n");
578 if (draft_msg != NULL) {
579 TnyHeader *header = tny_msg_get_header (draft_msg);
580 tny_folder_remove_msg (folder, header, NULL);
581 g_object_unref (header);
584 tny_folder_add_msg (folder, msg, &(priv->error));
590 g_object_unref (G_OBJECT(msg));
592 g_object_unref (G_OBJECT(folder));
594 modest_mail_operation_notify_end (self);
599 ModestMailOperation *mail_op;
600 TnyStoreAccount *account;
601 TnyTransportAccount *transport_account;
604 gchar *retrieve_type;
607 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
608 /* We use this folder observer to track the headers that have been
609 * added to a folder */
612 TnyList *new_headers;
613 } InternalFolderObserver;
617 } InternalFolderObserverClass;
619 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
621 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
622 internal_folder_observer,
624 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
628 foreach_add_item (gpointer header, gpointer user_data)
630 /* printf("DEBUG: %s: header subject=%s\n",
631 * __FUNCTION__, tny_header_get_subject(TNY_HEADER(header)));
633 tny_list_prepend (TNY_LIST (user_data),
634 g_object_ref (G_OBJECT (header)));
637 /* This is the method that looks for new messages in a folder */
639 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
641 InternalFolderObserver *derived = (InternalFolderObserver *)self;
643 TnyFolderChangeChanged changed;
645 changed = tny_folder_change_get_changed (change);
647 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
650 /* Get added headers */
651 list = tny_simple_list_new ();
652 tny_folder_change_get_added_headers (change, list);
654 /* printf ("DEBUG: %s: Calling foreach with a list of size=%d\n",
655 * __FUNCTION__, tny_list_get_length(list));
658 /* Add them to the folder observer */
659 tny_list_foreach (list, foreach_add_item,
660 derived->new_headers);
662 g_object_unref (G_OBJECT (list));
667 internal_folder_observer_init (InternalFolderObserver *self)
669 self->new_headers = tny_simple_list_new ();
672 internal_folder_observer_finalize (GObject *object)
674 InternalFolderObserver *self;
676 self = (InternalFolderObserver *) object;
677 g_object_unref (self->new_headers);
679 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
682 tny_folder_observer_init (TnyFolderObserverIface *iface)
684 iface->update_func = internal_folder_observer_update;
687 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
689 GObjectClass *object_class;
691 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
692 object_class = (GObjectClass*) klass;
693 object_class->finalize = internal_folder_observer_finalize;
699 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
702 TnyList *folders = tny_simple_list_new ();
704 tny_folder_store_get_folders (store, folders, query, NULL);
705 iter = tny_list_create_iterator (folders);
707 while (!tny_iterator_is_done (iter)) {
709 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
711 tny_list_prepend (all_folders, G_OBJECT (folder));
712 recurse_folders (folder, query, all_folders);
713 g_object_unref (G_OBJECT (folder));
715 tny_iterator_next (iter);
717 g_object_unref (G_OBJECT (iter));
718 g_object_unref (G_OBJECT (folders));
722 * Issues the "progress-changed" signal. The timer won't be removed,
723 * so you must call g_source_remove to stop the signal emission
726 idle_notify_progress (gpointer data)
728 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
729 ModestMailOperationState *state;
731 state = modest_mail_operation_clone_state (mail_op);
732 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
733 g_slice_free (ModestMailOperationState, state);
739 * Issues the "progress-changed" signal and removes the timer. It uses
740 * a lock to ensure that the progress information of the mail
741 * operation is not modified while there are notifications pending
744 idle_notify_progress_once (gpointer data)
748 pair = (ModestPair *) data;
750 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
752 /* Free the state and the reference to the mail operation */
753 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
754 g_object_unref (pair->first);
760 * Used by update_account_thread to notify the queue from the main
761 * loop. We call it inside an idle call to achieve that
764 notify_update_account_queue (gpointer data)
766 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
768 modest_mail_operation_notify_end (mail_op);
769 g_object_unref (mail_op);
775 compare_headers_by_date (gconstpointer a,
778 TnyHeader **header1, **header2;
781 header1 = (TnyHeader **) a;
782 header2 = (TnyHeader **) b;
784 sent1 = tny_header_get_date_sent (*header1);
785 sent2 = tny_header_get_date_sent (*header2);
787 /* We want the most recent ones (greater time_t) at the
796 update_account_thread (gpointer thr_user_data)
798 UpdateAccountInfo *info;
799 TnyList *all_folders = NULL;
800 GPtrArray *new_headers;
801 TnyIterator *iter = NULL;
802 TnyFolderStoreQuery *query = NULL;
803 ModestMailOperationPrivate *priv;
804 ModestTnySendQueue *send_queue;
806 info = (UpdateAccountInfo *) thr_user_data;
807 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
809 /* Get account and set it into mail_operation */
810 priv->account = g_object_ref (info->account);
812 /* Get all the folders. We can do it synchronously because
813 we're already running in a different thread than the UI */
814 all_folders = tny_simple_list_new ();
815 query = tny_folder_store_query_new ();
816 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
817 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
822 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
826 iter = tny_list_create_iterator (all_folders);
827 while (!tny_iterator_is_done (iter)) {
828 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
830 recurse_folders (folder, query, all_folders);
831 tny_iterator_next (iter);
833 g_object_unref (G_OBJECT (iter));
835 /* Update status and notify. We need to call the notification
836 with a source function in order to call it from the main
837 loop. We need that in order not to get into trouble with
838 Gtk+. We use a timeout in order to provide more status
839 information, because the sync tinymail call does not
840 provide it for the moment */
841 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
843 /* Refresh folders */
844 new_headers = g_ptr_array_new ();
845 iter = tny_list_create_iterator (all_folders);
846 while (!tny_iterator_is_done (iter) && !priv->error) {
848 InternalFolderObserver *observer;
849 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
851 /* Refresh the folder */
852 /* Our observer receives notification of new emails during folder refreshes,
853 * so we can use observer->new_headers.
854 * TODO: This does not seem to be providing accurate numbers.
855 * Possibly the observer is notified asynchronously.
857 observer = g_object_new (internal_folder_observer_get_type (), NULL);
858 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
860 /* This gets the status information (headers) from the server.
861 * We use the blocking version, because we are already in a separate
864 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
866 /* If the retrieve type is headers only do nothing more */
867 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
868 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
871 iter = tny_list_create_iterator (observer->new_headers);
872 while (!tny_iterator_is_done (iter)) {
873 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
874 /* printf (" DEBUG1.2 %s: checking size: account=%s, subject=%s\n",
875 * __FUNCTION__, tny_account_get_id (priv->account),
876 * tny_header_get_subject (header));
879 /* Apply per-message size limits */
880 if (tny_header_get_message_size (header) < info->max_size)
881 g_ptr_array_add (new_headers, g_object_ref (header));
883 g_object_unref (header);
884 tny_iterator_next (iter);
886 g_object_unref (iter);
889 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
890 g_object_unref (observer);
894 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
896 g_object_unref (G_OBJECT (folder));
897 tny_iterator_next (iter);
899 g_object_unref (G_OBJECT (iter));
900 g_source_remove (timeout);
902 if (new_headers->len > 0) {
906 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
908 /* Apply message count limit */
909 /* If the number of messages exceeds the maximum, ask the
910 * user to download them all,
911 * as per the UI spec "Retrieval Limits" section in 4.4:
913 printf ("DEBUG: %s: account=%s, len=%d, retrieve_limit = %d\n", __FUNCTION__,
914 tny_account_get_id (priv->account), new_headers->len, info->retrieve_limit);
915 if (new_headers->len > info->retrieve_limit) {
916 /* TODO: Ask the user, instead of just failing, showing mail_nc_msg_count_limit_exceeded,
917 * with 'Get all' and 'Newest only' buttons. */
918 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
919 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
920 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
921 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
922 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
927 priv->total = MIN (new_headers->len, info->retrieve_limit);
928 while (msg_num < priv->total) {
930 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
931 TnyFolder *folder = tny_header_get_folder (header);
932 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
933 ModestMailOperationState *state;
937 /* We can not just use the mail operation because the
938 values of done and total could change before the
940 state = modest_mail_operation_clone_state (info->mail_op);
941 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
942 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
943 pair, (GDestroyNotify) modest_pair_free);
945 g_object_unref (msg);
946 g_object_unref (folder);
950 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
951 g_ptr_array_free (new_headers, FALSE);
955 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
958 if (priv->account != NULL)
959 g_object_unref (priv->account);
960 priv->account = g_object_ref (info->transport_account);
962 send_queue = modest_runtime_get_send_queue (info->transport_account);
964 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
965 modest_tny_send_queue_try_to_send (send_queue);
966 g_source_remove (timeout);
968 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
969 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
970 "cannot create a send queue for %s\n",
971 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
972 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
975 /* Check if the operation was a success */
977 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
979 /* Update the last updated key */
980 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
981 tny_account_get_id (TNY_ACCOUNT (info->account)),
982 MODEST_ACCOUNT_LAST_UPDATED,
988 /* Notify about operation end. Note that the info could be
989 freed before this idle happens, but the mail operation will
991 g_idle_add (notify_update_account_queue, info->mail_op);
994 g_object_unref (query);
995 g_object_unref (all_folders);
996 g_object_unref (info->account);
997 g_object_unref (info->transport_account);
998 g_free (info->retrieve_type);
999 g_slice_free (UpdateAccountInfo, info);
1005 modest_mail_operation_update_account (ModestMailOperation *self,
1006 const gchar *account_name)
1009 UpdateAccountInfo *info;
1010 ModestMailOperationPrivate *priv;
1011 ModestAccountMgr *mgr;
1012 TnyStoreAccount *modest_account;
1013 TnyTransportAccount *transport_account;
1015 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1016 g_return_val_if_fail (account_name, FALSE);
1018 /* Make sure that we have a connection, and request one
1020 * TODO: Is there some way to trigger this for every attempt to
1021 * use the network? */
1022 if (!modest_platform_connect_and_wait(NULL))
1025 /* Init mail operation. Set total and done to 0, and do not
1026 update them, this way the progress objects will know that
1027 we have no clue about the number of the objects */
1028 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1031 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1033 /* Get the Modest account */
1034 modest_account = (TnyStoreAccount *)
1035 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
1037 TNY_ACCOUNT_TYPE_STORE);
1039 if (!modest_account) {
1040 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1041 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1042 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1043 "cannot get tny store account for %s\n", account_name);
1044 modest_mail_operation_notify_end (self);
1048 /* Get the transport account, we can not do it in the thread
1049 due to some problems with dbus */
1050 transport_account = (TnyTransportAccount *)
1051 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1053 if (!transport_account) {
1054 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1055 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1056 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1057 "cannot get tny transport account for %s\n", account_name);
1058 modest_mail_operation_notify_end (self);
1062 /* Create the helper object */
1063 info = g_slice_new (UpdateAccountInfo);
1064 info->mail_op = self;
1065 info->account = modest_account;
1066 info->transport_account = transport_account;
1068 /* Get the message size limit */
1069 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1070 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1071 if (info->max_size == 0)
1072 info->max_size = G_MAXINT;
1074 info->max_size = info->max_size * KB;
1076 /* Get per-account retrieval type */
1077 mgr = modest_runtime_get_account_mgr ();
1078 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1079 MODEST_ACCOUNT_RETRIEVE, FALSE);
1081 /* Get per-account message amount retrieval limit */
1082 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1083 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1084 if (info->retrieve_limit == 0)
1085 info->retrieve_limit = G_MAXINT;
1087 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1089 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1094 /* ******************************************************************* */
1095 /* ************************** STORE ACTIONS ************************* */
1096 /* ******************************************************************* */
1100 modest_mail_operation_create_folder (ModestMailOperation *self,
1101 TnyFolderStore *parent,
1104 ModestMailOperationPrivate *priv;
1105 TnyFolder *new_folder = NULL;
1107 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1108 g_return_val_if_fail (name, NULL);
1110 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1113 if (TNY_IS_FOLDER (parent)) {
1114 /* Check folder rules */
1115 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1116 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1117 /* Set status failed and set an error */
1118 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1119 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1120 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1121 _("mail_in_ui_folder_create_error"));
1126 /* Create the folder */
1127 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1128 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1130 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1133 /* Notify about operation end */
1134 modest_mail_operation_notify_end (self);
1140 modest_mail_operation_remove_folder (ModestMailOperation *self,
1142 gboolean remove_to_trash)
1144 TnyAccount *account;
1145 ModestMailOperationPrivate *priv;
1146 ModestTnyFolderRules rules;
1148 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1149 g_return_if_fail (TNY_IS_FOLDER (folder));
1151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1153 /* Check folder rules */
1154 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1155 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1156 /* Set status failed and set an error */
1157 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1158 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1159 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1160 _("mail_in_ui_folder_delete_error"));
1164 /* Get the account */
1165 account = tny_folder_get_account (folder);
1166 priv->account = g_object_ref(account);
1168 /* Delete folder or move to trash */
1169 if (remove_to_trash) {
1170 TnyFolder *trash_folder = NULL;
1171 trash_folder = modest_tny_account_get_special_folder (account,
1172 TNY_FOLDER_TYPE_TRASH);
1173 /* TODO: error_handling */
1174 modest_mail_operation_xfer_folder (self, folder,
1175 TNY_FOLDER_STORE (trash_folder), TRUE);
1177 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1179 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1180 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1183 g_object_unref (G_OBJECT (parent));
1185 g_object_unref (G_OBJECT (account));
1188 /* Notify about operation end */
1189 modest_mail_operation_notify_end (self);
1193 transfer_folder_status_cb (GObject *obj,
1197 ModestMailOperation *self;
1198 ModestMailOperationPrivate *priv;
1199 ModestMailOperationState *state;
1201 g_return_if_fail (status != NULL);
1202 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1204 self = MODEST_MAIL_OPERATION (user_data);
1205 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1207 if ((status->position == 1) && (status->of_total == 100))
1210 priv->done = status->position;
1211 priv->total = status->of_total;
1213 state = modest_mail_operation_clone_state (self);
1214 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1215 g_slice_free (ModestMailOperationState, state);
1220 transfer_folder_cb (TnyFolder *folder,
1221 TnyFolderStore *into,
1223 TnyFolder *new_folder, GError **err,
1226 ModestMailOperation *self = NULL;
1227 ModestMailOperationPrivate *priv = NULL;
1229 self = MODEST_MAIL_OPERATION (user_data);
1231 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1234 priv->error = g_error_copy (*err);
1236 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1237 } else if (cancelled) {
1238 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1239 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1240 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1241 _("Transference of %s was cancelled."),
1242 tny_folder_get_name (folder));
1245 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1249 g_object_unref (folder);
1250 g_object_unref (into);
1251 if (new_folder != NULL)
1252 g_object_unref (new_folder);
1254 /* Notify about operation end */
1255 modest_mail_operation_notify_end (self);
1259 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1261 TnyFolderStore *parent,
1262 gboolean delete_original)
1264 ModestMailOperationPrivate *priv = NULL;
1265 ModestTnyFolderRules parent_rules, rules;
1267 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1268 g_return_if_fail (TNY_IS_FOLDER (folder));
1269 g_return_if_fail (TNY_IS_FOLDER (parent));
1271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1273 /* Get account and set it into mail_operation */
1274 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1275 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1277 /* Get folder rules */
1278 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1279 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1281 if (!TNY_IS_FOLDER_STORE (parent)) {
1285 /* The moveable restriction is applied also to copy operation */
1286 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1287 /* Set status failed and set an error */
1288 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1289 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1290 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1291 _("mail_in_ui_folder_move_target_error"));
1293 /* Notify the queue */
1294 modest_mail_operation_notify_end (self);
1295 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1296 /* Set status failed and set an error */
1297 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1298 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1299 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1300 _("FIXME: parent folder does not accept new folders"));
1302 /* Notify the queue */
1303 modest_mail_operation_notify_end (self);
1305 /* Pick references for async calls */
1306 g_object_ref (folder);
1307 g_object_ref (parent);
1309 /* Move/Copy folder */
1310 tny_folder_copy_async (folder,
1312 tny_folder_get_name (folder),
1315 transfer_folder_status_cb,
1321 modest_mail_operation_rename_folder (ModestMailOperation *self,
1325 ModestMailOperationPrivate *priv;
1326 ModestTnyFolderRules rules;
1328 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1329 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1330 g_return_if_fail (name);
1332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1334 /* Get account and set it into mail_operation */
1335 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1337 /* Check folder rules */
1338 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1339 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1340 /* Set status failed and set an error */
1341 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1342 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1343 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1344 _("FIXME: unable to rename"));
1346 /* Notify about operation end */
1347 modest_mail_operation_notify_end (self);
1349 /* Rename. Camel handles folder subscription/unsubscription */
1350 TnyFolderStore *into;
1352 into = tny_folder_get_folder_store (folder);
1353 tny_folder_copy_async (folder, into, name, TRUE,
1355 transfer_folder_status_cb,
1358 g_object_unref (into);
1363 /* ******************************************************************* */
1364 /* ************************** MSG ACTIONS ************************* */
1365 /* ******************************************************************* */
1367 void modest_mail_operation_get_msg (ModestMailOperation *self,
1369 GetMsgAsyncUserCallback user_callback,
1372 GetMsgAsyncHelper *helper = NULL;
1374 ModestMailOperationPrivate *priv;
1376 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1377 g_return_if_fail (TNY_IS_HEADER (header));
1379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1380 folder = tny_header_get_folder (header);
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1384 /* Get message from folder */
1386 /* Get account and set it into mail_operation */
1387 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1389 helper = g_slice_new0 (GetMsgAsyncHelper);
1390 helper->mail_op = self;
1391 helper->user_callback = user_callback;
1392 helper->pending_ops = 1;
1393 helper->user_data = user_data;
1395 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1397 g_object_unref (G_OBJECT (folder));
1399 /* Set status failed and set an error */
1400 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1401 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1402 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1403 _("Error trying to get a message. No folder found for header"));
1405 /* Notify the queue */
1406 modest_mail_operation_notify_end (self);
1411 get_msg_cb (TnyFolder *folder,
1417 GetMsgAsyncHelper *helper = NULL;
1418 ModestMailOperation *self = NULL;
1419 ModestMailOperationPrivate *priv = NULL;
1421 helper = (GetMsgAsyncHelper *) user_data;
1422 g_return_if_fail (helper != NULL);
1423 self = helper->mail_op;
1424 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1427 helper->pending_ops--;
1429 /* Check errors and cancel */
1431 priv->error = g_error_copy (*error);
1432 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1436 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1437 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1438 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1439 _("Error trying to refresh the contents of %s"),
1440 tny_folder_get_name (folder));
1444 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1446 /* If user defined callback function was defined, call it */
1447 if (helper->user_callback) {
1448 helper->user_callback (self, NULL, msg, helper->user_data);
1453 if (helper->pending_ops == 0) {
1454 g_slice_free (GetMsgAsyncHelper, helper);
1456 /* Notify about operation end */
1457 modest_mail_operation_notify_end (self);
1462 get_msg_status_cb (GObject *obj,
1466 GetMsgAsyncHelper *helper = NULL;
1467 ModestMailOperation *self;
1468 ModestMailOperationPrivate *priv;
1469 ModestMailOperationState *state;
1471 g_return_if_fail (status != NULL);
1472 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1474 helper = (GetMsgAsyncHelper *) user_data;
1475 g_return_if_fail (helper != NULL);
1477 self = helper->mail_op;
1478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1480 if ((status->position == 1) && (status->of_total == 100))
1486 state = modest_mail_operation_clone_state (self);
1487 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1488 g_slice_free (ModestMailOperationState, state);
1491 /****************************************************/
1493 ModestMailOperation *mail_op;
1495 GetMsgAsyncUserCallback user_callback;
1497 GDestroyNotify notify;
1501 GetMsgAsyncUserCallback user_callback;
1505 ModestMailOperation *mail_op;
1506 } NotifyGetMsgsInfo;
1510 * Used by get_msgs_full_thread to call the user_callback for each
1511 * message that has been read
1514 notify_get_msgs_full (gpointer data)
1516 NotifyGetMsgsInfo *info;
1518 info = (NotifyGetMsgsInfo *) data;
1520 /* Call the user callback */
1521 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1523 g_slice_free (NotifyGetMsgsInfo, info);
1529 * Used by get_msgs_full_thread to free al the thread resources and to
1530 * call the destroy function for the passed user_data
1533 get_msgs_full_destroyer (gpointer data)
1535 GetFullMsgsInfo *info;
1537 info = (GetFullMsgsInfo *) data;
1540 info->notify (info->user_data);
1543 g_object_unref (info->headers);
1544 g_slice_free (GetFullMsgsInfo, info);
1550 get_msgs_full_thread (gpointer thr_user_data)
1552 GetFullMsgsInfo *info;
1553 ModestMailOperationPrivate *priv = NULL;
1554 TnyIterator *iter = NULL;
1556 info = (GetFullMsgsInfo *) thr_user_data;
1557 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1559 iter = tny_list_create_iterator (info->headers);
1560 while (!tny_iterator_is_done (iter)) {
1564 header = TNY_HEADER (tny_iterator_get_current (iter));
1565 folder = tny_header_get_folder (header);
1567 /* Get message from folder */
1570 /* The callback will call it per each header */
1571 msg = tny_folder_get_msg (folder, header, &(priv->error));
1574 ModestMailOperationState *state;
1579 /* notify progress */
1580 state = modest_mail_operation_clone_state (info->mail_op);
1581 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1582 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1583 pair, (GDestroyNotify) modest_pair_free);
1585 /* The callback is the responsible for
1586 freeing the message */
1587 if (info->user_callback) {
1588 NotifyGetMsgsInfo *info_notify;
1589 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1590 info_notify->user_callback = info->user_callback;
1591 info_notify->mail_op = info->mail_op;
1592 info_notify->header = g_object_ref (header);
1593 info_notify->msg = g_object_ref (msg);
1594 info_notify->user_data = info->user_data;
1595 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1596 notify_get_msgs_full,
1599 g_object_unref (msg);
1602 /* Set status failed and set an error */
1603 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1604 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1605 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1606 "Error trying to get a message. No folder found for header");
1608 g_object_unref (header);
1609 tny_iterator_next (iter);
1612 /* Set operation status */
1613 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
1614 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1616 /* Notify about operation end */
1617 g_idle_add (notify_update_account_queue, info->mail_op);
1619 /* Free thread resources. Will be called after all previous idles */
1620 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1626 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1627 TnyList *header_list,
1628 GetMsgAsyncUserCallback user_callback,
1630 GDestroyNotify notify)
1632 TnyHeader *header = NULL;
1633 TnyFolder *folder = NULL;
1635 ModestMailOperationPrivate *priv = NULL;
1636 GetFullMsgsInfo *info = NULL;
1637 gboolean size_ok = TRUE;
1639 TnyIterator *iter = NULL;
1641 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1643 /* Init mail operation */
1644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1645 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1647 priv->total = tny_list_get_length(header_list);
1649 /* Get account and set it into mail_operation */
1650 if (tny_list_get_length (header_list) >= 1) {
1651 iter = tny_list_create_iterator (header_list);
1652 header = TNY_HEADER (tny_iterator_get_current (iter));
1653 folder = tny_header_get_folder (header);
1654 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1655 g_object_unref (header);
1656 g_object_unref (folder);
1658 if (tny_list_get_length (header_list) == 1) {
1659 g_object_unref (iter);
1664 /* Get msg size limit */
1665 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1666 MODEST_CONF_MSG_SIZE_LIMIT,
1669 g_clear_error (&(priv->error));
1670 max_size = G_MAXINT;
1672 max_size = max_size * KB;
1675 /* Check message size limits. If there is only one message
1676 always retrieve it */
1678 while (!tny_iterator_is_done (iter) && size_ok) {
1679 header = TNY_HEADER (tny_iterator_get_current (iter));
1680 if (tny_header_get_message_size (header) >= max_size)
1682 g_object_unref (header);
1683 tny_iterator_next (iter);
1685 g_object_unref (iter);
1689 /* Create the info */
1690 info = g_slice_new0 (GetFullMsgsInfo);
1691 info->mail_op = self;
1692 info->user_callback = user_callback;
1693 info->user_data = user_data;
1694 info->headers = g_object_ref (header_list);
1695 info->notify = notify;
1697 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1699 /* Set status failed and set an error */
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1701 /* FIXME: the error msg is different for pop */
1702 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1703 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
1704 _("emev_ni_ui_imap_msg_size_exceed_error"));
1705 /* Remove from queue and free resources */
1706 modest_mail_operation_notify_end (self);
1714 modest_mail_operation_remove_msg (ModestMailOperation *self,
1716 gboolean remove_to_trash)
1719 ModestMailOperationPrivate *priv;
1721 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1722 g_return_if_fail (TNY_IS_HEADER (header));
1724 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1725 folder = tny_header_get_folder (header);
1727 /* Get account and set it into mail_operation */
1728 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1730 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1732 /* Delete or move to trash */
1733 if (remove_to_trash) {
1734 TnyFolder *trash_folder;
1735 TnyStoreAccount *store_account;
1737 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1738 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1739 TNY_FOLDER_TYPE_TRASH);
1744 headers = tny_simple_list_new ();
1745 tny_list_append (headers, G_OBJECT (header));
1746 g_object_unref (header);
1749 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1750 g_object_unref (headers);
1751 /* g_object_unref (trash_folder); */
1753 ModestMailOperationPrivate *priv;
1755 /* Set status failed and set an error */
1756 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1760 _("Error trying to delete a message. Trash folder not found"));
1763 g_object_unref (G_OBJECT (store_account));
1765 tny_folder_remove_msg (folder, header, &(priv->error));
1767 tny_folder_sync(folder, TRUE, &(priv->error));
1772 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1774 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1777 g_object_unref (G_OBJECT (folder));
1779 /* Notify about operation end */
1780 modest_mail_operation_notify_end (self);
1784 transfer_msgs_status_cb (GObject *obj,
1788 XFerMsgAsyncHelper *helper = NULL;
1789 ModestMailOperation *self;
1790 ModestMailOperationPrivate *priv;
1791 ModestMailOperationState *state;
1794 g_return_if_fail (status != NULL);
1795 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1797 helper = (XFerMsgAsyncHelper *) user_data;
1798 g_return_if_fail (helper != NULL);
1800 self = helper->mail_op;
1801 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1803 if ((status->position == 1) && (status->of_total == 100))
1806 priv->done = status->position;
1807 priv->total = status->of_total;
1809 state = modest_mail_operation_clone_state (self);
1810 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1811 g_slice_free (ModestMailOperationState, state);
1816 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1818 XFerMsgAsyncHelper *helper;
1819 ModestMailOperation *self;
1820 ModestMailOperationPrivate *priv;
1822 helper = (XFerMsgAsyncHelper *) user_data;
1823 self = helper->mail_op;
1825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1828 priv->error = g_error_copy (*err);
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1831 } else if (cancelled) {
1832 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1833 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1834 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1835 _("Error trying to refresh the contents of %s"),
1836 tny_folder_get_name (folder));
1839 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1842 /* If user defined callback function was defined, call it */
1843 if (helper->user_callback) {
1844 helper->user_callback (priv->source, helper->user_data);
1848 g_object_unref (helper->headers);
1849 g_object_unref (helper->dest_folder);
1850 g_object_unref (helper->mail_op);
1851 g_slice_free (XFerMsgAsyncHelper, helper);
1852 g_object_unref (folder);
1854 /* Notify about operation end */
1855 modest_mail_operation_notify_end (self);
1859 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1862 gboolean delete_original,
1863 XferMsgsAsynUserCallback user_callback,
1866 ModestMailOperationPrivate *priv;
1868 TnyFolder *src_folder;
1869 XFerMsgAsyncHelper *helper;
1871 ModestTnyFolderRules rules;
1873 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1874 g_return_if_fail (TNY_IS_LIST (headers));
1875 g_return_if_fail (TNY_IS_FOLDER (folder));
1877 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1880 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1882 /* Apply folder rules */
1883 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1885 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1886 /* Set status failed and set an error */
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1890 _("FIXME: folder does not accept msgs"));
1891 /* Notify the queue */
1892 modest_mail_operation_notify_end (self);
1896 /* Create the helper */
1897 helper = g_slice_new0 (XFerMsgAsyncHelper);
1898 helper->mail_op = g_object_ref(self);
1899 helper->dest_folder = g_object_ref(folder);
1900 helper->headers = g_object_ref(headers);
1901 helper->user_callback = user_callback;
1902 helper->user_data = user_data;
1904 /* Get source folder */
1905 iter = tny_list_create_iterator (headers);
1906 header = TNY_HEADER (tny_iterator_get_current (iter));
1907 src_folder = tny_header_get_folder (header);
1908 g_object_unref (header);
1909 g_object_unref (iter);
1911 /* Get account and set it into mail_operation */
1912 priv->account = tny_folder_get_account (src_folder);
1914 /* Transfer messages */
1915 tny_folder_transfer_msgs_async (src_folder,
1920 transfer_msgs_status_cb,
1926 on_refresh_folder (TnyFolder *folder,
1931 ModestMailOperation *self;
1932 ModestMailOperationPrivate *priv;
1934 self = MODEST_MAIL_OPERATION (user_data);
1935 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1938 priv->error = g_error_copy (*error);
1939 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1944 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1945 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1946 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1947 _("Error trying to refresh the contents of %s"),
1948 tny_folder_get_name (folder));
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1956 g_object_unref (folder);
1958 /* Notify about operation end */
1959 modest_mail_operation_notify_end (self);
1963 on_refresh_folder_status_update (GObject *obj,
1967 ModestMailOperation *self;
1968 ModestMailOperationPrivate *priv;
1969 ModestMailOperationState *state;
1971 g_return_if_fail (status != NULL);
1972 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1974 self = MODEST_MAIL_OPERATION (user_data);
1975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1977 priv->done = status->position;
1978 priv->total = status->of_total;
1980 state = modest_mail_operation_clone_state (self);
1981 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1982 g_slice_free (ModestMailOperationState, state);
1986 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1989 ModestMailOperationPrivate *priv;
1991 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1993 /* Pick a reference */
1994 g_object_ref (folder);
1996 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1998 /* Get account and set it into mail_operation */
1999 priv->account = tny_folder_get_account (folder);
2001 /* Refresh the folder. TODO: tinymail could issue a status
2002 updates before the callback call then this could happen. We
2003 must review the design */
2004 tny_folder_refresh_async (folder,
2006 on_refresh_folder_status_update,
2012 * It's used by the mail operation queue to notify the observers
2013 * attached to that signal that the operation finished. We need to use
2014 * that because tinymail does not give us the progress of a given
2015 * operation when it finishes (it directly calls the operation
2019 modest_mail_operation_notify_end (ModestMailOperation *self)
2021 ModestMailOperationState *state;
2023 /* Notify the observers about the mail opertation end */
2024 state = modest_mail_operation_clone_state (self);
2025 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2026 g_slice_free (ModestMailOperationState, state);