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.
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
34 #include <tny-mime-part.h>
35 #include <tny-store-account.h>
36 #include <tny-folder-store.h>
37 #include <tny-folder-store-query.h>
38 #include <tny-camel-stream.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <tny-folder-observer.h>
43 #include <camel/camel-stream-mem.h>
44 #include <glib/gi18n.h>
45 #include "modest-platform.h"
46 #include <modest-tny-account.h>
47 #include <modest-tny-send-queue.h>
48 #include <modest-runtime.h>
49 #include "modest-text-utils.h"
50 #include "modest-tny-msg.h"
51 #include "modest-tny-folder.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-marshal.h"
54 #include "modest-error.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 enum _ModestMailOperationSignals
77 PROGRESS_CHANGED_SIGNAL,
82 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
83 struct _ModestMailOperationPrivate {
89 ErrorCheckingUserCallback error_checking;
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->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
183 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
185 priv->error_checking = NULL;
193 modest_mail_operation_finalize (GObject *obj)
195 ModestMailOperationPrivate *priv;
197 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
200 g_error_free (priv->error);
204 g_object_unref (priv->source);
208 G_OBJECT_CLASS(parent_class)->finalize (obj);
212 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
215 ModestMailOperation *obj;
216 ModestMailOperationPrivate *priv;
218 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
219 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
221 priv->op_type = op_type;
223 priv->source = g_object_ref(source);
229 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
231 ErrorCheckingUserCallback error_handler)
233 ModestMailOperation *obj;
234 ModestMailOperationPrivate *priv;
236 obj = modest_mail_operation_new (op_type, source);
237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
239 g_return_val_if_fail (error_handler != NULL, obj);
240 priv->error_checking = error_handler;
246 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
248 ModestMailOperationPrivate *priv;
250 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
251 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
253 if (priv->error_checking == NULL)
255 priv->error_checking (priv->source, self);
259 ModestMailOperationTypeOperation
260 modest_mail_operation_get_type_operation (ModestMailOperation *self)
262 ModestMailOperationPrivate *priv;
264 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
266 return priv->op_type;
270 modest_mail_operation_is_mine (ModestMailOperation *self,
273 ModestMailOperationPrivate *priv;
275 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
276 if (priv->source == NULL) return FALSE;
278 return priv->source == me;
282 modest_mail_operation_get_source (ModestMailOperation *self)
284 ModestMailOperationPrivate *priv;
286 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
288 return g_object_ref (priv->source);
291 ModestMailOperationStatus
292 modest_mail_operation_get_status (ModestMailOperation *self)
294 ModestMailOperationPrivate *priv;
296 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
297 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
298 MODEST_MAIL_OPERATION_STATUS_INVALID);
300 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
305 modest_mail_operation_get_error (ModestMailOperation *self)
307 ModestMailOperationPrivate *priv;
309 g_return_val_if_fail (self, NULL);
310 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
312 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
317 modest_mail_operation_cancel (ModestMailOperation *self)
319 ModestMailOperationPrivate *priv;
321 if (!MODEST_IS_MAIL_OPERATION (self)) {
322 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
328 /* TODO: Tinymail does not support cancel operation */
329 /* tny_account_cancel (); */
332 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
334 /* Notify about operation end */
335 modest_mail_operation_notify_end (self);
341 modest_mail_operation_get_task_done (ModestMailOperation *self)
343 ModestMailOperationPrivate *priv;
345 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
347 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
352 modest_mail_operation_get_task_total (ModestMailOperation *self)
354 ModestMailOperationPrivate *priv;
356 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
363 modest_mail_operation_is_finished (ModestMailOperation *self)
365 ModestMailOperationPrivate *priv;
366 gboolean retval = FALSE;
368 if (!MODEST_IS_MAIL_OPERATION (self)) {
369 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
373 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
375 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
376 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
377 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
378 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
388 modest_mail_operation_get_id (ModestMailOperation *self)
390 ModestMailOperationPrivate *priv;
392 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
394 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
399 modest_mail_operation_set_id (ModestMailOperation *self,
402 ModestMailOperationPrivate *priv;
404 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
411 * Creates an image of the current state of a mail operation, the
412 * caller must free it
414 static ModestMailOperationState *
415 modest_mail_operation_clone_state (ModestMailOperation *self)
417 ModestMailOperationState *state;
418 ModestMailOperationPrivate *priv;
420 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
422 state = g_slice_new (ModestMailOperationState);
424 state->status = priv->status;
425 state->op_type = priv->op_type;
426 state->done = priv->done;
427 state->total = priv->total;
428 state->finished = modest_mail_operation_is_finished (self);
433 /* ******************************************************************* */
434 /* ************************** SEND ACTIONS ************************* */
435 /* ******************************************************************* */
438 modest_mail_operation_send_mail (ModestMailOperation *self,
439 TnyTransportAccount *transport_account,
442 TnySendQueue *send_queue;
444 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
445 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
446 g_return_if_fail (TNY_IS_MSG (msg));
448 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
449 if (!TNY_IS_SEND_QUEUE(send_queue))
450 g_printerr ("modest: could not find send queue for account\n");
453 tny_send_queue_add (send_queue, msg, &err);
455 g_printerr ("modest: error adding msg to send queue: %s\n",
459 /* g_message ("modest: message added to send queue"); */
463 /* Notify about operation end */
464 modest_mail_operation_notify_end (self);
468 modest_mail_operation_send_new_mail (ModestMailOperation *self,
469 TnyTransportAccount *transport_account,
470 const gchar *from, const gchar *to,
471 const gchar *cc, const gchar *bcc,
472 const gchar *subject, const gchar *plain_body,
473 const gchar *html_body,
474 const GList *attachments_list,
475 TnyHeaderFlags priority_flags)
478 ModestMailOperationPrivate *priv = NULL;
479 /* GList *node = NULL; */
481 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
482 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
486 /* Check parametters */
488 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
489 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
490 _("Error trying to send a mail. You need to set at least one recipient"));
494 if (html_body == NULL) {
495 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
497 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
500 g_printerr ("modest: failed to create a new msg\n");
504 /* TODO: add priority handling. It's received in the priority_flags operator, and
505 it should have effect in the sending operation */
507 /* Call mail operation */
508 modest_mail_operation_send_mail (self, transport_account, new_msg);
511 g_object_unref (G_OBJECT (new_msg));
515 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
516 TnyTransportAccount *transport_account,
517 const gchar *from, const gchar *to,
518 const gchar *cc, const gchar *bcc,
519 const gchar *subject, const gchar *plain_body,
520 const gchar *html_body,
521 const GList *attachments_list,
522 TnyHeaderFlags priority_flags)
525 TnyFolder *folder = NULL;
526 ModestMailOperationPrivate *priv = NULL;
529 /* GList *node = NULL; */
531 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
532 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
534 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
536 if (html_body == NULL) {
537 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
539 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
542 g_printerr ("modest: failed to create a new msg\n");
546 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
548 g_printerr ("modest: failed to find Drafts folder\n");
552 tny_folder_add_msg (folder, msg, &err);
554 g_printerr ("modest: error adding msg to Drafts folder: %s",
560 modest_mail_operation_notify_end (self);
565 g_object_unref (G_OBJECT(msg));
567 g_object_unref (G_OBJECT(folder));
572 ModestMailOperation *mail_op;
573 TnyStoreAccount *account;
574 TnyTransportAccount *transport_account;
577 gchar *retrieve_type;
580 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
581 /* We use this folder observer to track the headers that have been
582 * added to a folder */
585 TnyList *new_headers;
586 } InternalFolderObserver;
590 } InternalFolderObserverClass;
592 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
594 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
595 internal_folder_observer,
597 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
601 foreach_add_item (gpointer header, gpointer user_data)
603 tny_list_prepend (TNY_LIST (user_data),
604 g_object_ref (G_OBJECT (header)));
607 /* This is the method that looks for new messages in a folder */
609 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
611 TnyFolderChangeChanged changed;
613 changed = tny_folder_change_get_changed (change);
615 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
618 /* Get added headers */
619 list = tny_simple_list_new ();
620 tny_folder_change_get_added_headers (change, list);
622 /* Add them to the folder observer */
623 tny_list_foreach (list, foreach_add_item,
624 ((InternalFolderObserver *)self)->new_headers);
626 g_object_unref (G_OBJECT (list));
631 internal_folder_observer_init (InternalFolderObserver *self)
633 self->new_headers = tny_simple_list_new ();
636 internal_folder_observer_finalize (GObject *object)
638 InternalFolderObserver *self;
640 self = (InternalFolderObserver *) object;
641 g_object_unref (self->new_headers);
643 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
646 tny_folder_observer_init (TnyFolderObserverIface *iface)
648 iface->update_func = internal_folder_observer_update;
651 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
653 GObjectClass *object_class;
655 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
656 object_class = (GObjectClass*) klass;
657 object_class->finalize = internal_folder_observer_finalize;
663 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
666 TnyList *folders = tny_simple_list_new ();
668 tny_folder_store_get_folders (store, folders, query, NULL);
669 iter = tny_list_create_iterator (folders);
671 while (!tny_iterator_is_done (iter)) {
673 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
675 tny_list_prepend (all_folders, G_OBJECT (folder));
676 recurse_folders (folder, query, all_folders);
677 g_object_unref (G_OBJECT (folder));
679 tny_iterator_next (iter);
681 g_object_unref (G_OBJECT (iter));
682 g_object_unref (G_OBJECT (folders));
686 * Issues the "progress-changed" signal. The timer won't be removed,
687 * so you must call g_source_remove to stop the signal emission
690 idle_notify_progress (gpointer data)
692 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
693 ModestMailOperationState *state;
695 state = modest_mail_operation_clone_state (mail_op);
696 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
697 g_slice_free (ModestMailOperationState, state);
703 * Issues the "progress-changed" signal and removes the timer. It uses
704 * a lock to ensure that the progress information of the mail
705 * operation is not modified while there are notifications pending
708 idle_notify_progress_once (gpointer data)
712 pair = (ModestPair *) data;
714 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
716 /* Free the state and the reference to the mail operation */
717 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
718 g_object_unref (pair->first);
724 * Used by update_account_thread to notify the queue from the main
725 * loop. We call it inside an idle call to achieve that
728 notify_update_account_queue (gpointer data)
730 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
732 modest_mail_operation_notify_end (mail_op);
733 g_object_unref (mail_op);
739 compare_headers_by_date (gconstpointer a,
742 TnyHeader **header1, **header2;
745 header1 = (TnyHeader **) a;
746 header2 = (TnyHeader **) b;
748 sent1 = tny_header_get_date_sent (*header1);
749 sent2 = tny_header_get_date_sent (*header2);
751 /* We want the most recent ones (greater time_t) at the
760 update_account_thread (gpointer thr_user_data)
762 UpdateAccountInfo *info;
763 TnyList *all_folders = NULL;
764 GPtrArray *new_headers;
765 TnyIterator *iter = NULL;
766 TnyFolderStoreQuery *query = NULL;
767 ModestMailOperationPrivate *priv;
769 info = (UpdateAccountInfo *) thr_user_data;
770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
772 /* Get all the folders We can do it synchronously because
773 we're already running in a different thread than the UI */
774 all_folders = tny_simple_list_new ();
775 query = tny_folder_store_query_new ();
776 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
777 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
782 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
786 iter = tny_list_create_iterator (all_folders);
787 while (!tny_iterator_is_done (iter)) {
788 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
790 recurse_folders (folder, query, all_folders);
791 tny_iterator_next (iter);
793 g_object_unref (G_OBJECT (iter));
795 /* Update status and notify. We need to call the notification
796 with a source functopm in order to call it from the main
797 loop. We need that in order not to get into trouble with
798 Gtk+. We use a timeout in order to provide more status
799 information, because the sync tinymail call does not
800 provide it for the moment */
801 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
803 /* Refresh folders */
804 new_headers = g_ptr_array_new ();
805 iter = tny_list_create_iterator (all_folders);
806 while (!tny_iterator_is_done (iter) && !priv->error) {
808 InternalFolderObserver *observer;
809 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
811 /* Refresh the folder */
812 observer = g_object_new (internal_folder_observer_get_type (), NULL);
813 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
814 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
816 /* If the retrieve type is headers only do nothing more */
817 if (!strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
818 !strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
821 iter = tny_list_create_iterator (observer->new_headers);
822 while (!tny_iterator_is_done (iter)) {
823 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
824 /* Apply per-message size limits */
825 if (tny_header_get_message_size (header) < info->max_size)
826 g_ptr_array_add (new_headers, g_object_ref (header));
828 g_object_unref (header);
829 tny_iterator_next (iter);
831 g_object_unref (iter);
833 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
834 g_object_unref (observer);
837 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
839 g_object_unref (G_OBJECT (folder));
840 tny_iterator_next (iter);
842 g_object_unref (G_OBJECT (iter));
843 g_source_remove (timeout);
845 if (new_headers->len > 0) {
849 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
851 /* Apply message count limit */
852 /* TODO if the number of messages exceeds the maximum, ask the
853 user to download them all */
855 priv->total = MIN (new_headers->len, info->retrieve_limit);
856 while ((msg_num < info->retrieve_limit)) {
858 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
859 TnyFolder *folder = tny_header_get_folder (header);
860 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
861 ModestMailOperationState *state;
865 /* We can not just use the mail operation because the
866 values of done and total could change before the
868 state = modest_mail_operation_clone_state (info->mail_op);
869 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
870 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
871 pair, (GDestroyNotify) modest_pair_free);
873 g_object_unref (msg);
874 g_object_unref (folder);
878 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
879 g_ptr_array_free (new_headers, FALSE);
883 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
887 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
888 (info->transport_account);
890 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
891 /* TODO: Is this meant to block? */
892 modest_tny_send_queue_try_to_send (send_queue);
893 g_source_remove (timeout);
895 g_object_unref (G_OBJECT(send_queue));
897 /* Check if the operation was a success */
899 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
901 /* Update the last updated key */
902 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
903 tny_account_get_id (TNY_ACCOUNT (info->account)),
904 MODEST_ACCOUNT_LAST_UPDATED,
910 /* Notify about operation end. Note that the info could be
911 freed before this idle happens, but the mail operation will
913 g_idle_add (notify_update_account_queue, info->mail_op);
916 g_object_unref (query);
917 g_object_unref (all_folders);
918 g_object_unref (info->account);
919 g_object_unref (info->transport_account);
920 g_free (info->retrieve_type);
921 g_slice_free (UpdateAccountInfo, info);
927 modest_mail_operation_update_account (ModestMailOperation *self,
928 const gchar *account_name)
931 UpdateAccountInfo *info;
932 ModestMailOperationPrivate *priv;
933 ModestAccountMgr *mgr;
934 TnyStoreAccount *modest_account;
935 TnyTransportAccount *transport_account;
937 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
938 g_return_val_if_fail (account_name, FALSE);
940 /* Init mail operation. Set total and done to 0, and do not
941 update them, this way the progress objects will know that
942 we have no clue about the number of the objects */
943 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
946 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
948 /* Get the Modest account */
949 modest_account = (TnyStoreAccount *)
950 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
952 TNY_ACCOUNT_TYPE_STORE);
954 if (!modest_account) {
955 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
956 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
957 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
958 "cannot get tny store account for %s\n", account_name);
959 modest_mail_operation_notify_end (self);
963 /* Get the transport account, we can not do it in the thread
964 due to some problems with dbus */
965 transport_account = (TnyTransportAccount *)
966 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
968 if (!transport_account) {
969 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
970 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
971 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
972 "cannot get tny transport account for %s\n", account_name);
973 modest_mail_operation_notify_end (self);
977 /* Create the helper object */
978 info = g_slice_new (UpdateAccountInfo);
979 info->mail_op = self;
980 info->account = modest_account;
981 info->transport_account = transport_account;
983 /* Get the message size limit */
984 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
985 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
986 if (info->max_size == 0)
987 info->max_size = G_MAXINT;
989 info->max_size = info->max_size * KB;
991 /* Get per-account retrieval type */
992 mgr = modest_runtime_get_account_mgr ();
993 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
994 MODEST_ACCOUNT_RETRIEVE, FALSE);
996 /* Get per-account message amount retrieval limit */
997 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
998 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
999 if (info->retrieve_limit == 0)
1000 info->retrieve_limit = G_MAXINT;
1002 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1007 /* ******************************************************************* */
1008 /* ************************** STORE ACTIONS ************************* */
1009 /* ******************************************************************* */
1013 modest_mail_operation_create_folder (ModestMailOperation *self,
1014 TnyFolderStore *parent,
1017 ModestTnyFolderRules rules;
1018 ModestMailOperationPrivate *priv;
1019 TnyFolder *new_folder = NULL;
1020 gboolean can_create = FALSE;
1022 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1023 g_return_val_if_fail (name, NULL);
1025 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1028 if (!TNY_IS_FOLDER (parent)) {
1029 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1030 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1031 _("mail_in_ui_folder_create_error"));
1033 /* Check folder rules */
1034 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1035 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
1036 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1037 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1038 _("mail_in_ui_folder_create_error"));
1044 /* Create the folder */
1045 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1046 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1049 /* Notify about operation end */
1050 modest_mail_operation_notify_end (self);
1056 modest_mail_operation_remove_folder (ModestMailOperation *self,
1058 gboolean remove_to_trash)
1060 TnyAccount *account;
1061 ModestMailOperationPrivate *priv;
1062 ModestTnyFolderRules rules;
1064 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1065 g_return_if_fail (TNY_IS_FOLDER (folder));
1067 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1069 /* Check folder rules */
1070 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1071 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1072 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1073 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1074 _("mail_in_ui_folder_delete_error"));
1078 /* Get the account */
1079 account = tny_folder_get_account (folder);
1081 /* Delete folder or move to trash */
1082 if (remove_to_trash) {
1083 TnyFolder *trash_folder = NULL;
1084 trash_folder = modest_tny_account_get_special_folder (account,
1085 TNY_FOLDER_TYPE_TRASH);
1086 /* TODO: error_handling */
1087 modest_mail_operation_xfer_folder (self, folder,
1088 TNY_FOLDER_STORE (trash_folder), TRUE);
1090 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1092 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1093 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1096 g_object_unref (G_OBJECT (parent));
1098 g_object_unref (G_OBJECT (account));
1101 /* Notify about operation end */
1102 modest_mail_operation_notify_end (self);
1106 modest_mail_operation_rename_folder (ModestMailOperation *self,
1110 ModestMailOperationPrivate *priv;
1111 ModestTnyFolderRules rules;
1113 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1114 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1115 g_return_if_fail (name);
1117 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1119 /* Check folder rules */
1120 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1121 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1122 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1123 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1124 _("FIXME: unable to rename"));
1126 /* Rename. Camel handles folder subscription/unsubscription */
1127 TnyFolderStore *into;
1130 into = tny_folder_get_folder_store (folder);
1131 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
1133 g_object_unref (into);
1135 g_object_unref (nfol);
1137 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1141 /* Notify about operation end */
1142 modest_mail_operation_notify_end (self);
1146 transfer_folder_status_cb (GObject *obj,
1150 ModestMailOperation *self;
1151 ModestMailOperationPrivate *priv;
1152 ModestMailOperationState *state;
1154 g_return_if_fail (status != NULL);
1155 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1157 self = MODEST_MAIL_OPERATION (user_data);
1158 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1160 if ((status->position == 1) && (status->of_total == 100))
1163 priv->done = status->position;
1164 priv->total = status->of_total;
1166 state = modest_mail_operation_clone_state (self);
1167 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1168 g_slice_free (ModestMailOperationState, state);
1173 transfer_folder_cb (TnyFolder *folder,
1174 TnyFolderStore *into,
1176 TnyFolder *new_folder, GError **err,
1179 ModestMailOperation *self = NULL;
1180 ModestMailOperationPrivate *priv = NULL;
1182 self = MODEST_MAIL_OPERATION (user_data);
1184 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1187 priv->error = g_error_copy (*err);
1189 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1190 } else if (cancelled) {
1191 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1192 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1193 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1194 _("Transference of %s was cancelled."),
1195 tny_folder_get_name (folder));
1198 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1202 g_object_unref (folder);
1203 g_object_unref (into);
1204 if (new_folder != NULL)
1205 g_object_unref (new_folder);
1207 /* Notify about operation end */
1208 modest_mail_operation_notify_end (self);
1212 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1214 TnyFolderStore *parent,
1215 gboolean delete_original)
1217 ModestMailOperationPrivate *priv = NULL;
1218 ModestTnyFolderRules parent_rules, rules;
1220 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1221 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1222 g_return_if_fail (TNY_IS_FOLDER (folder));
1224 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1226 /* Get folder rules */
1227 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1228 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1230 /* The moveable restriction is applied also to copy operation */
1231 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
1232 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1233 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1234 _("mail_in_ui_folder_move_target_error"));
1236 /* Notify the queue */
1237 modest_mail_operation_notify_end (self);
1238 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1239 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1240 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1241 _("FIXME: parent folder does not accept new folders"));
1243 /* Notify the queue */
1244 modest_mail_operation_notify_end (self);
1246 /* Pick references for async calls */
1247 g_object_ref (folder);
1248 g_object_ref (parent);
1250 /* Move/Copy folder */
1251 tny_folder_copy_async (folder,
1253 tny_folder_get_name (folder),
1256 transfer_folder_status_cb,
1262 /* ******************************************************************* */
1263 /* ************************** MSG ACTIONS ************************* */
1264 /* ******************************************************************* */
1266 void modest_mail_operation_get_msg (ModestMailOperation *self,
1268 GetMsgAsyncUserCallback user_callback,
1271 GetMsgAsyncHelper *helper = NULL;
1273 ModestMailOperationPrivate *priv;
1275 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1276 g_return_if_fail (TNY_IS_HEADER (header));
1278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1279 folder = tny_header_get_folder (header);
1281 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1283 /* Get message from folder */
1285 helper = g_slice_new0 (GetMsgAsyncHelper);
1286 helper->mail_op = self;
1287 helper->user_callback = user_callback;
1288 helper->pending_ops = 1;
1289 helper->user_data = user_data;
1291 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1293 g_object_unref (G_OBJECT (folder));
1295 /* Set status failed and set an error */
1296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1297 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1298 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1299 _("Error trying to get a message. No folder found for header"));
1304 get_msg_cb (TnyFolder *folder,
1310 GetMsgAsyncHelper *helper = NULL;
1311 ModestMailOperation *self = NULL;
1312 ModestMailOperationPrivate *priv = NULL;
1314 helper = (GetMsgAsyncHelper *) user_data;
1315 g_return_if_fail (helper != NULL);
1316 self = helper->mail_op;
1317 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1320 helper->pending_ops--;
1322 /* Check errors and cancel */
1324 priv->error = g_error_copy (*error);
1325 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1329 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1330 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1331 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1332 _("Error trying to refresh the contents of %s"),
1333 tny_folder_get_name (folder));
1337 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1339 /* If user defined callback function was defined, call it */
1340 if (helper->user_callback) {
1341 helper->user_callback (self, NULL, msg, helper->user_data);
1346 if (helper->pending_ops == 0) {
1347 g_slice_free (GetMsgAsyncHelper, helper);
1349 /* Notify about operation end */
1350 modest_mail_operation_notify_end (self);
1355 get_msg_status_cb (GObject *obj,
1359 GetMsgAsyncHelper *helper = NULL;
1360 ModestMailOperation *self;
1361 ModestMailOperationPrivate *priv;
1362 ModestMailOperationState *state;
1364 g_return_if_fail (status != NULL);
1365 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1367 helper = (GetMsgAsyncHelper *) user_data;
1368 g_return_if_fail (helper != NULL);
1370 self = helper->mail_op;
1371 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1373 if ((status->position == 1) && (status->of_total == 100))
1379 state = modest_mail_operation_clone_state (self);
1380 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1381 g_slice_free (ModestMailOperationState, state);
1384 /****************************************************/
1386 ModestMailOperation *mail_op;
1388 GetMsgAsyncUserCallback user_callback;
1390 GDestroyNotify notify;
1394 GetMsgAsyncUserCallback user_callback;
1398 ModestMailOperation *mail_op;
1399 } NotifyGetMsgsInfo;
1403 * Used by get_msgs_full_thread to call the user_callback for each
1404 * message that has been read
1407 notify_get_msgs_full (gpointer data)
1409 NotifyGetMsgsInfo *info;
1411 info = (NotifyGetMsgsInfo *) data;
1413 /* Call the user callback */
1414 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1416 g_slice_free (NotifyGetMsgsInfo, info);
1422 * Used by get_msgs_full_thread to free al the thread resources and to
1423 * call the destroy function for the passed user_data
1426 get_msgs_full_destroyer (gpointer data)
1428 GetFullMsgsInfo *info;
1430 info = (GetFullMsgsInfo *) data;
1433 info->notify (info->user_data);
1436 g_object_unref (info->headers);
1437 g_slice_free (GetFullMsgsInfo, info);
1443 get_msgs_full_thread (gpointer thr_user_data)
1445 GetFullMsgsInfo *info;
1446 ModestMailOperationPrivate *priv = NULL;
1447 TnyIterator *iter = NULL;
1449 info = (GetFullMsgsInfo *) thr_user_data;
1450 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1452 iter = tny_list_create_iterator (info->headers);
1453 while (!tny_iterator_is_done (iter)) {
1457 header = TNY_HEADER (tny_iterator_get_current (iter));
1458 folder = tny_header_get_folder (header);
1460 /* Get message from folder */
1463 /* The callback will call it per each header */
1464 msg = tny_folder_get_msg (folder, header, &(priv->error));
1467 ModestMailOperationState *state;
1472 /* notify progress */
1473 state = modest_mail_operation_clone_state (info->mail_op);
1474 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1475 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1476 pair, (GDestroyNotify) modest_pair_free);
1478 /* The callback is the responsible for
1479 freeing the message */
1480 if (info->user_callback) {
1481 NotifyGetMsgsInfo *info_notify;
1482 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1483 info_notify->user_callback = info->user_callback;
1484 info_notify->mail_op = info->mail_op;
1485 info_notify->header = g_object_ref (header);
1486 info_notify->msg = g_object_ref (msg);
1487 info_notify->user_data = info->user_data;
1488 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1489 notify_get_msgs_full,
1492 g_object_unref (msg);
1495 /* Set status failed and set an error */
1496 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1497 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1498 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1499 "Error trying to get a message. No folder found for header");
1501 g_object_unref (header);
1502 tny_iterator_next (iter);
1505 /* Notify about operation end */
1506 g_idle_add (notify_update_account_queue, info->mail_op);
1508 /* Free thread resources. Will be called after all previous idles */
1509 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1515 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1516 TnyList *header_list,
1517 GetMsgAsyncUserCallback user_callback,
1519 GDestroyNotify notify)
1522 ModestMailOperationPrivate *priv = NULL;
1523 GetFullMsgsInfo *info = NULL;
1524 gboolean size_ok = TRUE;
1526 GError *error = NULL;
1528 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1530 /* Init mail operation */
1531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1532 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1534 priv->total = tny_list_get_length(header_list);
1536 /* Get msg size limit */
1537 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1538 MODEST_CONF_MSG_SIZE_LIMIT,
1541 g_clear_error (&error);
1542 max_size = G_MAXINT;
1544 max_size = max_size * KB;
1547 /* Check message size limits. If there is only one message
1548 always retrieve it */
1549 if (tny_list_get_length (header_list) > 1) {
1552 iter = tny_list_create_iterator (header_list);
1553 while (!tny_iterator_is_done (iter) && size_ok) {
1554 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1555 if (tny_header_get_message_size (header) >= max_size)
1557 g_object_unref (header);
1558 tny_iterator_next (iter);
1560 g_object_unref (iter);
1564 /* Create the info */
1565 info = g_slice_new0 (GetFullMsgsInfo);
1566 info->mail_op = self;
1567 info->user_callback = user_callback;
1568 info->user_data = user_data;
1569 info->headers = g_object_ref (header_list);
1570 info->notify = notify;
1572 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1574 /* FIXME: the error msg is different for pop */
1575 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1576 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1577 _("emev_ni_ui_imap_msg_sizelimit_error"));
1578 /* Remove from queue and free resources */
1579 modest_mail_operation_notify_end (self);
1587 modest_mail_operation_remove_msg (ModestMailOperation *self,
1589 gboolean remove_to_trash)
1592 ModestMailOperationPrivate *priv;
1594 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1595 g_return_if_fail (TNY_IS_HEADER (header));
1597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1598 folder = tny_header_get_folder (header);
1600 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1602 /* Delete or move to trash */
1603 if (remove_to_trash) {
1604 TnyFolder *trash_folder;
1605 TnyStoreAccount *store_account;
1607 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1608 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1609 TNY_FOLDER_TYPE_TRASH);
1614 headers = tny_simple_list_new ();
1615 tny_list_append (headers, G_OBJECT (header));
1616 g_object_unref (header);
1619 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1620 g_object_unref (headers);
1621 /* g_object_unref (trash_folder); */
1623 ModestMailOperationPrivate *priv;
1625 /* Set status failed and set an error */
1626 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1628 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1629 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1630 _("Error trying to delete a message. Trash folder not found"));
1633 g_object_unref (G_OBJECT (store_account));
1635 tny_folder_remove_msg (folder, header, &(priv->error));
1637 tny_folder_sync(folder, TRUE, &(priv->error));
1642 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1644 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1647 g_object_unref (G_OBJECT (folder));
1649 /* Notify about operation end */
1650 modest_mail_operation_notify_end (self);
1654 transfer_msgs_status_cb (GObject *obj,
1658 XFerMsgAsyncHelper *helper = NULL;
1659 ModestMailOperation *self;
1660 ModestMailOperationPrivate *priv;
1661 ModestMailOperationState *state;
1664 g_return_if_fail (status != NULL);
1665 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1667 helper = (XFerMsgAsyncHelper *) user_data;
1668 g_return_if_fail (helper != NULL);
1670 self = helper->mail_op;
1671 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1673 if ((status->position == 1) && (status->of_total == 100))
1676 priv->done = status->position;
1677 priv->total = status->of_total;
1679 state = modest_mail_operation_clone_state (self);
1680 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1681 g_slice_free (ModestMailOperationState, state);
1686 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1688 XFerMsgAsyncHelper *helper;
1689 ModestMailOperation *self;
1690 ModestMailOperationPrivate *priv;
1692 helper = (XFerMsgAsyncHelper *) user_data;
1693 self = helper->mail_op;
1695 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1698 priv->error = g_error_copy (*err);
1700 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1701 } else if (cancelled) {
1702 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1703 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1704 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1705 _("Error trying to refresh the contents of %s"),
1706 tny_folder_get_name (folder));
1709 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1712 /* If user defined callback function was defined, call it */
1713 if (helper->user_callback) {
1714 helper->user_callback (priv->source, helper->user_data);
1718 g_object_unref (helper->headers);
1719 g_object_unref (helper->dest_folder);
1720 g_object_unref (helper->mail_op);
1721 g_slice_free (XFerMsgAsyncHelper, helper);
1722 g_object_unref (folder);
1724 /* Notify about operation end */
1725 modest_mail_operation_notify_end (self);
1729 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1732 gboolean delete_original,
1733 XferMsgsAsynUserCallback user_callback,
1736 ModestMailOperationPrivate *priv;
1738 TnyFolder *src_folder;
1739 XFerMsgAsyncHelper *helper;
1741 ModestTnyFolderRules rules;
1743 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1744 g_return_if_fail (TNY_IS_LIST (headers));
1745 g_return_if_fail (TNY_IS_FOLDER (folder));
1747 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1752 /* Apply folder rules */
1753 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1755 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1756 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1757 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1758 _("FIXME: folder does not accept msgs"));
1759 /* Notify the queue */
1760 modest_mail_operation_notify_end (self);
1764 /* Create the helper */
1765 helper = g_slice_new0 (XFerMsgAsyncHelper);
1766 helper->mail_op = g_object_ref(self);
1767 helper->dest_folder = g_object_ref(folder);
1768 helper->headers = g_object_ref(headers);
1769 helper->user_callback = user_callback;
1770 helper->user_data = user_data;
1772 /* Get source folder */
1773 iter = tny_list_create_iterator (headers);
1774 header = TNY_HEADER (tny_iterator_get_current (iter));
1775 src_folder = tny_header_get_folder (header);
1776 g_object_unref (header);
1777 g_object_unref (iter);
1779 /* Transfer messages */
1780 tny_folder_transfer_msgs_async (src_folder,
1785 transfer_msgs_status_cb,
1791 on_refresh_folder (TnyFolder *folder,
1796 ModestMailOperation *self;
1797 ModestMailOperationPrivate *priv;
1799 self = MODEST_MAIL_OPERATION (user_data);
1800 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1803 priv->error = g_error_copy (*error);
1804 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
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));
1817 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1821 g_object_unref (folder);
1823 /* Notify about operation end */
1824 modest_mail_operation_notify_end (self);
1828 on_refresh_folder_status_update (GObject *obj,
1832 ModestMailOperation *self;
1833 ModestMailOperationPrivate *priv;
1834 ModestMailOperationState *state;
1836 g_return_if_fail (status != NULL);
1837 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1839 self = MODEST_MAIL_OPERATION (user_data);
1840 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1842 priv->done = status->position;
1843 priv->total = status->of_total;
1845 state = modest_mail_operation_clone_state (self);
1846 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1847 g_slice_free (ModestMailOperationState, state);
1851 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1854 ModestMailOperationPrivate *priv;
1856 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1858 /* Pick a reference */
1859 g_object_ref (folder);
1861 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1863 /* Refresh the folder. TODO: tinymail could issue a status
1864 updates before the callback call then this could happen. We
1865 must review the design */
1866 tny_folder_refresh_async (folder,
1868 on_refresh_folder_status_update,
1874 * It's used by the mail operation queue to notify the observers
1875 * attached to that signal that the operation finished. We need to use
1876 * that because tinymail does not give us the progress of a given
1877 * operation when it finishes (it directly calls the operation
1881 modest_mail_operation_notify_end (ModestMailOperation *self)
1883 ModestMailOperationState *state;
1885 /* Notify the observers about the mail opertation end */
1886 state = modest_mail_operation_clone_state (self);
1887 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1888 g_slice_free (ModestMailOperationState, state);
1890 /* Notify the queue */
1891 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);