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 < priv->total)) {
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 modest_tny_send_queue_try_to_send (send_queue);
892 g_source_remove (timeout);
894 g_object_unref (G_OBJECT(send_queue));
896 /* Check if the operation was a success */
898 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
900 /* Update the last updated key */
901 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
902 tny_account_get_id (TNY_ACCOUNT (info->account)),
903 MODEST_ACCOUNT_LAST_UPDATED,
909 /* Notify about operation end. Note that the info could be
910 freed before this idle happens, but the mail operation will
912 g_idle_add (notify_update_account_queue, info->mail_op);
915 g_object_unref (query);
916 g_object_unref (all_folders);
917 g_object_unref (info->account);
918 g_object_unref (info->transport_account);
919 g_free (info->retrieve_type);
920 g_slice_free (UpdateAccountInfo, info);
926 modest_mail_operation_update_account (ModestMailOperation *self,
927 const gchar *account_name)
930 UpdateAccountInfo *info;
931 ModestMailOperationPrivate *priv;
932 ModestAccountMgr *mgr;
933 TnyStoreAccount *modest_account;
934 TnyTransportAccount *transport_account;
936 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
937 g_return_val_if_fail (account_name, FALSE);
939 /* Init mail operation. Set total and done to 0, and do not
940 update them, this way the progress objects will know that
941 we have no clue about the number of the objects */
942 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
945 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
947 /* Get the Modest account */
948 modest_account = (TnyStoreAccount *)
949 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
951 TNY_ACCOUNT_TYPE_STORE);
953 if (!modest_account) {
954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
955 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
956 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
957 "cannot get tny store account for %s\n", account_name);
958 modest_mail_operation_notify_end (self);
962 /* Get the transport account, we can not do it in the thread
963 due to some problems with dbus */
964 transport_account = (TnyTransportAccount *)
965 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
967 if (!transport_account) {
968 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
969 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
970 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
971 "cannot get tny transport account for %s\n", account_name);
972 modest_mail_operation_notify_end (self);
976 /* Create the helper object */
977 info = g_slice_new (UpdateAccountInfo);
978 info->mail_op = self;
979 info->account = modest_account;
980 info->transport_account = transport_account;
982 /* Get the message size limit */
983 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
984 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
985 if (info->max_size == 0)
986 info->max_size = G_MAXINT;
988 info->max_size = info->max_size * KB;
990 /* Get per-account retrieval type */
991 mgr = modest_runtime_get_account_mgr ();
992 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
993 MODEST_ACCOUNT_RETRIEVE, FALSE);
995 /* Get per-account message amount retrieval limit */
996 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
997 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
998 if (info->retrieve_limit == 0)
999 info->retrieve_limit = G_MAXINT;
1001 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1006 /* ******************************************************************* */
1007 /* ************************** STORE ACTIONS ************************* */
1008 /* ******************************************************************* */
1012 modest_mail_operation_create_folder (ModestMailOperation *self,
1013 TnyFolderStore *parent,
1016 ModestTnyFolderRules rules;
1017 ModestMailOperationPrivate *priv;
1018 TnyFolder *new_folder = NULL;
1019 gboolean can_create = FALSE;
1021 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1022 g_return_val_if_fail (name, NULL);
1024 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1027 if (!TNY_IS_FOLDER (parent)) {
1028 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1029 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1030 _("mail_in_ui_folder_create_error"));
1032 /* Check folder rules */
1033 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1034 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
1035 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1036 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1037 _("mail_in_ui_folder_create_error"));
1043 /* Create the folder */
1044 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1045 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1048 /* Notify about operation end */
1049 modest_mail_operation_notify_end (self);
1055 modest_mail_operation_remove_folder (ModestMailOperation *self,
1057 gboolean remove_to_trash)
1059 TnyAccount *account;
1060 ModestMailOperationPrivate *priv;
1061 ModestTnyFolderRules rules;
1063 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1064 g_return_if_fail (TNY_IS_FOLDER (folder));
1066 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1068 /* Check folder rules */
1069 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1070 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1071 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1072 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1073 _("mail_in_ui_folder_delete_error"));
1077 /* Get the account */
1078 account = tny_folder_get_account (folder);
1080 /* Delete folder or move to trash */
1081 if (remove_to_trash) {
1082 TnyFolder *trash_folder = NULL;
1083 trash_folder = modest_tny_account_get_special_folder (account,
1084 TNY_FOLDER_TYPE_TRASH);
1085 /* TODO: error_handling */
1086 modest_mail_operation_xfer_folder (self, folder,
1087 TNY_FOLDER_STORE (trash_folder), TRUE);
1089 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1091 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1092 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1095 g_object_unref (G_OBJECT (parent));
1097 g_object_unref (G_OBJECT (account));
1100 /* Notify about operation end */
1101 modest_mail_operation_notify_end (self);
1105 modest_mail_operation_rename_folder (ModestMailOperation *self,
1109 ModestMailOperationPrivate *priv;
1110 ModestTnyFolderRules rules;
1112 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1113 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1114 g_return_if_fail (name);
1116 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1118 /* Check folder rules */
1119 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1120 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1121 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1122 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1123 _("FIXME: unable to rename"));
1125 /* Rename. Camel handles folder subscription/unsubscription */
1126 TnyFolderStore *into;
1129 into = tny_folder_get_folder_store (folder);
1130 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
1132 g_object_unref (into);
1134 g_object_unref (nfol);
1136 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1140 /* Notify about operation end */
1141 modest_mail_operation_notify_end (self);
1145 transfer_folder_status_cb (GObject *obj,
1149 ModestMailOperation *self;
1150 ModestMailOperationPrivate *priv;
1151 ModestMailOperationState *state;
1153 g_return_if_fail (status != NULL);
1154 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1156 self = MODEST_MAIL_OPERATION (user_data);
1157 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1159 if ((status->position == 1) && (status->of_total == 100))
1162 priv->done = status->position;
1163 priv->total = status->of_total;
1165 state = modest_mail_operation_clone_state (self);
1166 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1167 g_slice_free (ModestMailOperationState, state);
1172 transfer_folder_cb (TnyFolder *folder,
1173 TnyFolderStore *into,
1175 TnyFolder *new_folder, GError **err,
1178 ModestMailOperation *self = NULL;
1179 ModestMailOperationPrivate *priv = NULL;
1181 self = MODEST_MAIL_OPERATION (user_data);
1183 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1186 priv->error = g_error_copy (*err);
1188 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1189 } else if (cancelled) {
1190 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1191 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1192 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1193 _("Transference of %s was cancelled."),
1194 tny_folder_get_name (folder));
1197 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1201 g_object_unref (folder);
1202 g_object_unref (into);
1203 if (new_folder != NULL)
1204 g_object_unref (new_folder);
1206 /* Notify about operation end */
1207 modest_mail_operation_notify_end (self);
1211 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1213 TnyFolderStore *parent,
1214 gboolean delete_original)
1216 ModestMailOperationPrivate *priv = NULL;
1217 ModestTnyFolderRules parent_rules, rules;
1219 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1220 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1221 g_return_if_fail (TNY_IS_FOLDER (folder));
1223 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1225 /* Get folder rules */
1226 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1227 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1229 /* The moveable restriction is applied also to copy operation */
1230 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
1231 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1232 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1233 _("mail_in_ui_folder_move_target_error"));
1235 /* Notify the queue */
1236 modest_mail_operation_notify_end (self);
1237 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1238 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1239 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1240 _("FIXME: parent folder does not accept new folders"));
1242 /* Notify the queue */
1243 modest_mail_operation_notify_end (self);
1245 /* Pick references for async calls */
1246 g_object_ref (folder);
1247 g_object_ref (parent);
1249 /* Move/Copy folder */
1250 tny_folder_copy_async (folder,
1252 tny_folder_get_name (folder),
1255 transfer_folder_status_cb,
1261 /* ******************************************************************* */
1262 /* ************************** MSG ACTIONS ************************* */
1263 /* ******************************************************************* */
1265 void modest_mail_operation_get_msg (ModestMailOperation *self,
1267 GetMsgAsyncUserCallback user_callback,
1270 GetMsgAsyncHelper *helper = NULL;
1272 ModestMailOperationPrivate *priv;
1274 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1275 g_return_if_fail (TNY_IS_HEADER (header));
1277 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1278 folder = tny_header_get_folder (header);
1280 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1282 /* Get message from folder */
1284 helper = g_slice_new0 (GetMsgAsyncHelper);
1285 helper->mail_op = self;
1286 helper->user_callback = user_callback;
1287 helper->pending_ops = 1;
1288 helper->user_data = user_data;
1290 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1292 g_object_unref (G_OBJECT (folder));
1294 /* Set status failed and set an error */
1295 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1296 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1297 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1298 _("Error trying to get a message. No folder found for header"));
1303 get_msg_cb (TnyFolder *folder,
1309 GetMsgAsyncHelper *helper = NULL;
1310 ModestMailOperation *self = NULL;
1311 ModestMailOperationPrivate *priv = NULL;
1313 helper = (GetMsgAsyncHelper *) user_data;
1314 g_return_if_fail (helper != NULL);
1315 self = helper->mail_op;
1316 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1319 helper->pending_ops--;
1321 /* Check errors and cancel */
1323 priv->error = g_error_copy (*error);
1324 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1328 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1330 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1331 _("Error trying to refresh the contents of %s"),
1332 tny_folder_get_name (folder));
1336 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1338 /* If user defined callback function was defined, call it */
1339 if (helper->user_callback) {
1340 helper->user_callback (self, NULL, msg, helper->user_data);
1345 if (helper->pending_ops == 0) {
1346 g_slice_free (GetMsgAsyncHelper, helper);
1348 /* Notify about operation end */
1349 modest_mail_operation_notify_end (self);
1354 get_msg_status_cb (GObject *obj,
1358 GetMsgAsyncHelper *helper = NULL;
1359 ModestMailOperation *self;
1360 ModestMailOperationPrivate *priv;
1361 ModestMailOperationState *state;
1363 g_return_if_fail (status != NULL);
1364 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1366 helper = (GetMsgAsyncHelper *) user_data;
1367 g_return_if_fail (helper != NULL);
1369 self = helper->mail_op;
1370 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1372 if ((status->position == 1) && (status->of_total == 100))
1378 state = modest_mail_operation_clone_state (self);
1379 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1380 g_slice_free (ModestMailOperationState, state);
1383 /****************************************************/
1385 ModestMailOperation *mail_op;
1387 GetMsgAsyncUserCallback user_callback;
1389 GDestroyNotify notify;
1393 GetMsgAsyncUserCallback user_callback;
1397 ModestMailOperation *mail_op;
1398 } NotifyGetMsgsInfo;
1402 * Used by get_msgs_full_thread to call the user_callback for each
1403 * message that has been read
1406 notify_get_msgs_full (gpointer data)
1408 NotifyGetMsgsInfo *info;
1410 info = (NotifyGetMsgsInfo *) data;
1412 /* Call the user callback */
1413 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1415 g_slice_free (NotifyGetMsgsInfo, info);
1421 * Used by get_msgs_full_thread to free al the thread resources and to
1422 * call the destroy function for the passed user_data
1425 get_msgs_full_destroyer (gpointer data)
1427 GetFullMsgsInfo *info;
1429 info = (GetFullMsgsInfo *) data;
1432 info->notify (info->user_data);
1435 g_object_unref (info->headers);
1436 g_slice_free (GetFullMsgsInfo, info);
1442 get_msgs_full_thread (gpointer thr_user_data)
1444 GetFullMsgsInfo *info;
1445 ModestMailOperationPrivate *priv = NULL;
1446 TnyIterator *iter = NULL;
1448 info = (GetFullMsgsInfo *) thr_user_data;
1449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1451 iter = tny_list_create_iterator (info->headers);
1452 while (!tny_iterator_is_done (iter)) {
1456 header = TNY_HEADER (tny_iterator_get_current (iter));
1457 folder = tny_header_get_folder (header);
1459 /* Get message from folder */
1462 /* The callback will call it per each header */
1463 msg = tny_folder_get_msg (folder, header, &(priv->error));
1466 ModestMailOperationState *state;
1471 /* notify progress */
1472 state = modest_mail_operation_clone_state (info->mail_op);
1473 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1474 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1475 pair, (GDestroyNotify) modest_pair_free);
1477 /* The callback is the responsible for
1478 freeing the message */
1479 if (info->user_callback) {
1480 NotifyGetMsgsInfo *info_notify;
1481 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1482 info_notify->user_callback = info->user_callback;
1483 info_notify->mail_op = info->mail_op;
1484 info_notify->header = g_object_ref (header);
1485 info_notify->msg = g_object_ref (msg);
1486 info_notify->user_data = info->user_data;
1487 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1488 notify_get_msgs_full,
1491 g_object_unref (msg);
1494 /* Set status failed and set an error */
1495 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1496 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1497 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1498 "Error trying to get a message. No folder found for header");
1500 g_object_unref (header);
1501 tny_iterator_next (iter);
1504 /* Notify about operation end */
1505 g_idle_add (notify_update_account_queue, info->mail_op);
1507 /* Free thread resources. Will be called after all previous idles */
1508 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1514 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1515 TnyList *header_list,
1516 GetMsgAsyncUserCallback user_callback,
1518 GDestroyNotify notify)
1521 ModestMailOperationPrivate *priv = NULL;
1522 GetFullMsgsInfo *info = NULL;
1523 gboolean size_ok = TRUE;
1525 GError *error = NULL;
1527 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1529 /* Init mail operation */
1530 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1531 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1533 priv->total = tny_list_get_length(header_list);
1535 /* Get msg size limit */
1536 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1537 MODEST_CONF_MSG_SIZE_LIMIT,
1540 g_clear_error (&error);
1541 max_size = G_MAXINT;
1543 max_size = max_size * KB;
1546 /* Check message size limits. If there is only one message
1547 always retrieve it */
1548 if (tny_list_get_length (header_list) > 1) {
1551 iter = tny_list_create_iterator (header_list);
1552 while (!tny_iterator_is_done (iter) && size_ok) {
1553 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1554 if (tny_header_get_message_size (header) >= max_size)
1556 g_object_unref (header);
1557 tny_iterator_next (iter);
1559 g_object_unref (iter);
1563 /* Create the info */
1564 info = g_slice_new0 (GetFullMsgsInfo);
1565 info->mail_op = self;
1566 info->user_callback = user_callback;
1567 info->user_data = user_data;
1568 info->headers = g_object_ref (header_list);
1569 info->notify = notify;
1571 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1573 /* FIXME: the error msg is different for pop */
1574 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1575 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1576 _("emev_ni_ui_imap_msg_sizelimit_error"));
1577 /* Remove from queue and free resources */
1578 modest_mail_operation_notify_end (self);
1586 modest_mail_operation_remove_msg (ModestMailOperation *self,
1588 gboolean remove_to_trash)
1591 ModestMailOperationPrivate *priv;
1593 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1594 g_return_if_fail (TNY_IS_HEADER (header));
1596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1597 folder = tny_header_get_folder (header);
1599 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1601 /* Delete or move to trash */
1602 if (remove_to_trash) {
1603 TnyFolder *trash_folder;
1604 TnyStoreAccount *store_account;
1606 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1607 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1608 TNY_FOLDER_TYPE_TRASH);
1613 headers = tny_simple_list_new ();
1614 tny_list_append (headers, G_OBJECT (header));
1615 g_object_unref (header);
1618 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1619 g_object_unref (headers);
1620 /* g_object_unref (trash_folder); */
1622 ModestMailOperationPrivate *priv;
1624 /* Set status failed and set an error */
1625 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1626 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1627 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1628 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1629 _("Error trying to delete a message. Trash folder not found"));
1632 g_object_unref (G_OBJECT (store_account));
1634 tny_folder_remove_msg (folder, header, &(priv->error));
1636 tny_folder_sync(folder, TRUE, &(priv->error));
1641 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1643 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1646 g_object_unref (G_OBJECT (folder));
1648 /* Notify about operation end */
1649 modest_mail_operation_notify_end (self);
1653 transfer_msgs_status_cb (GObject *obj,
1657 XFerMsgAsyncHelper *helper = NULL;
1658 ModestMailOperation *self;
1659 ModestMailOperationPrivate *priv;
1660 ModestMailOperationState *state;
1663 g_return_if_fail (status != NULL);
1664 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1666 helper = (XFerMsgAsyncHelper *) user_data;
1667 g_return_if_fail (helper != NULL);
1669 self = helper->mail_op;
1670 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1672 if ((status->position == 1) && (status->of_total == 100))
1675 priv->done = status->position;
1676 priv->total = status->of_total;
1678 state = modest_mail_operation_clone_state (self);
1679 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1680 g_slice_free (ModestMailOperationState, state);
1685 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1687 XFerMsgAsyncHelper *helper;
1688 ModestMailOperation *self;
1689 ModestMailOperationPrivate *priv;
1691 helper = (XFerMsgAsyncHelper *) user_data;
1692 self = helper->mail_op;
1694 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1697 priv->error = g_error_copy (*err);
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1700 } else if (cancelled) {
1701 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1702 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1703 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1704 _("Error trying to refresh the contents of %s"),
1705 tny_folder_get_name (folder));
1708 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1711 /* If user defined callback function was defined, call it */
1712 if (helper->user_callback) {
1713 helper->user_callback (priv->source, helper->user_data);
1717 g_object_unref (helper->headers);
1718 g_object_unref (helper->dest_folder);
1719 g_object_unref (helper->mail_op);
1720 g_slice_free (XFerMsgAsyncHelper, helper);
1721 g_object_unref (folder);
1723 /* Notify about operation end */
1724 modest_mail_operation_notify_end (self);
1728 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1731 gboolean delete_original,
1732 XferMsgsAsynUserCallback user_callback,
1735 ModestMailOperationPrivate *priv;
1737 TnyFolder *src_folder;
1738 XFerMsgAsyncHelper *helper;
1740 ModestTnyFolderRules rules;
1742 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1743 g_return_if_fail (TNY_IS_LIST (headers));
1744 g_return_if_fail (TNY_IS_FOLDER (folder));
1746 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1751 /* Apply folder rules */
1752 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1754 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1756 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1757 _("FIXME: folder does not accept msgs"));
1758 /* Notify the queue */
1759 modest_mail_operation_notify_end (self);
1763 /* Create the helper */
1764 helper = g_slice_new0 (XFerMsgAsyncHelper);
1765 helper->mail_op = g_object_ref(self);
1766 helper->dest_folder = g_object_ref(folder);
1767 helper->headers = g_object_ref(headers);
1768 helper->user_callback = user_callback;
1769 helper->user_data = user_data;
1771 /* Get source folder */
1772 iter = tny_list_create_iterator (headers);
1773 header = TNY_HEADER (tny_iterator_get_current (iter));
1774 src_folder = tny_header_get_folder (header);
1775 g_object_unref (header);
1776 g_object_unref (iter);
1778 /* Transfer messages */
1779 tny_folder_transfer_msgs_async (src_folder,
1784 transfer_msgs_status_cb,
1790 on_refresh_folder (TnyFolder *folder,
1795 ModestMailOperation *self;
1796 ModestMailOperationPrivate *priv;
1798 self = MODEST_MAIL_OPERATION (user_data);
1799 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1802 priv->error = g_error_copy (*error);
1803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1809 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1810 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1811 _("Error trying to refresh the contents of %s"),
1812 tny_folder_get_name (folder));
1816 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1820 g_object_unref (folder);
1822 /* Notify about operation end */
1823 modest_mail_operation_notify_end (self);
1827 on_refresh_folder_status_update (GObject *obj,
1831 ModestMailOperation *self;
1832 ModestMailOperationPrivate *priv;
1833 ModestMailOperationState *state;
1835 g_return_if_fail (status != NULL);
1836 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1838 self = MODEST_MAIL_OPERATION (user_data);
1839 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1841 priv->done = status->position;
1842 priv->total = status->of_total;
1844 state = modest_mail_operation_clone_state (self);
1845 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1846 g_slice_free (ModestMailOperationState, state);
1850 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1853 ModestMailOperationPrivate *priv;
1855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1857 /* Pick a reference */
1858 g_object_ref (folder);
1860 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1862 /* Refresh the folder. TODO: tinymail could issue a status
1863 updates before the callback call then this could happen. We
1864 must review the design */
1865 tny_folder_refresh_async (folder,
1867 on_refresh_folder_status_update,
1873 * It's used by the mail operation queue to notify the observers
1874 * attached to that signal that the operation finished. We need to use
1875 * that because tinymail does not give us the progress of a given
1876 * operation when it finishes (it directly calls the operation
1880 modest_mail_operation_notify_end (ModestMailOperation *self)
1882 ModestMailOperationState *state;
1884 /* Notify the observers about the mail opertation end */
1885 state = modest_mail_operation_clone_state (self);
1886 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1887 g_slice_free (ModestMailOperationState, state);
1889 /* Notify the queue */
1890 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);