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;
118 typedef struct _XFerFolderAsyncHelper
120 ModestMailOperation *mail_op;
122 } XFerFolderAsyncHelper;
125 static GObjectClass *parent_class = NULL;
127 static guint signals[NUM_SIGNALS] = {0};
130 modest_mail_operation_get_type (void)
132 static GType my_type = 0;
134 static const GTypeInfo my_info = {
135 sizeof(ModestMailOperationClass),
136 NULL, /* base init */
137 NULL, /* base finalize */
138 (GClassInitFunc) modest_mail_operation_class_init,
139 NULL, /* class finalize */
140 NULL, /* class data */
141 sizeof(ModestMailOperation),
143 (GInstanceInitFunc) modest_mail_operation_init,
146 my_type = g_type_register_static (G_TYPE_OBJECT,
147 "ModestMailOperation",
154 modest_mail_operation_class_init (ModestMailOperationClass *klass)
156 GObjectClass *gobject_class;
157 gobject_class = (GObjectClass*) klass;
159 parent_class = g_type_class_peek_parent (klass);
160 gobject_class->finalize = modest_mail_operation_finalize;
162 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
165 * ModestMailOperation::progress-changed
166 * @self: the #MailOperation that emits the signal
167 * @user_data: user data set when the signal handler was connected
169 * Emitted when the progress of a mail operation changes
171 signals[PROGRESS_CHANGED_SIGNAL] =
172 g_signal_new ("progress-changed",
173 G_TYPE_FROM_CLASS (gobject_class),
175 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
177 g_cclosure_marshal_VOID__POINTER,
178 G_TYPE_NONE, 1, G_TYPE_POINTER);
182 modest_mail_operation_init (ModestMailOperation *obj)
184 ModestMailOperationPrivate *priv;
186 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
188 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
191 priv->error_checking = NULL;
199 modest_mail_operation_finalize (GObject *obj)
201 ModestMailOperationPrivate *priv;
203 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
206 g_error_free (priv->error);
210 g_object_unref (priv->source);
214 G_OBJECT_CLASS(parent_class)->finalize (obj);
218 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
221 ModestMailOperation *obj;
222 ModestMailOperationPrivate *priv;
224 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
225 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
227 priv->op_type = op_type;
229 priv->source = g_object_ref(source);
235 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
237 ErrorCheckingUserCallback error_handler)
239 ModestMailOperation *obj;
240 ModestMailOperationPrivate *priv;
242 obj = modest_mail_operation_new (op_type, source);
243 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
245 g_return_val_if_fail (error_handler != NULL, obj);
246 priv->error_checking = error_handler;
252 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
254 ModestMailOperationPrivate *priv;
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
257 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
259 if (priv->error_checking == NULL)
261 priv->error_checking (priv->source, self);
265 ModestMailOperationTypeOperation
266 modest_mail_operation_get_type_operation (ModestMailOperation *self)
268 ModestMailOperationPrivate *priv;
270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
272 return priv->op_type;
276 modest_mail_operation_is_mine (ModestMailOperation *self,
279 ModestMailOperationPrivate *priv;
281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
282 if (priv->source == NULL) return FALSE;
284 return priv->source == me;
288 modest_mail_operation_get_source (ModestMailOperation *self)
290 ModestMailOperationPrivate *priv;
292 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
294 return g_object_ref (priv->source);
297 ModestMailOperationStatus
298 modest_mail_operation_get_status (ModestMailOperation *self)
300 ModestMailOperationPrivate *priv;
302 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
303 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
304 MODEST_MAIL_OPERATION_STATUS_INVALID);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
311 modest_mail_operation_get_error (ModestMailOperation *self)
313 ModestMailOperationPrivate *priv;
315 g_return_val_if_fail (self, NULL);
316 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
323 modest_mail_operation_cancel (ModestMailOperation *self)
325 ModestMailOperationPrivate *priv;
327 if (!MODEST_IS_MAIL_OPERATION (self)) {
328 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
334 /* TODO: Tinymail does not support cancel operation */
335 /* tny_account_cancel (); */
338 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
340 /* Notify about operation end */
341 modest_mail_operation_notify_end (self);
347 modest_mail_operation_get_task_done (ModestMailOperation *self)
349 ModestMailOperationPrivate *priv;
351 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
358 modest_mail_operation_get_task_total (ModestMailOperation *self)
360 ModestMailOperationPrivate *priv;
362 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
369 modest_mail_operation_is_finished (ModestMailOperation *self)
371 ModestMailOperationPrivate *priv;
372 gboolean retval = FALSE;
374 if (!MODEST_IS_MAIL_OPERATION (self)) {
375 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
381 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
382 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
384 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
394 modest_mail_operation_get_id (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
405 modest_mail_operation_set_id (ModestMailOperation *self,
408 ModestMailOperationPrivate *priv;
410 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
417 * Creates an image of the current state of a mail operation, the
418 * caller must free it
420 static ModestMailOperationState *
421 modest_mail_operation_clone_state (ModestMailOperation *self)
423 ModestMailOperationState *state;
424 ModestMailOperationPrivate *priv;
426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
428 state = g_slice_new (ModestMailOperationState);
430 state->status = priv->status;
431 state->op_type = priv->op_type;
432 state->done = priv->done;
433 state->total = priv->total;
434 state->finished = modest_mail_operation_is_finished (self);
439 /* ******************************************************************* */
440 /* ************************** SEND ACTIONS ************************* */
441 /* ******************************************************************* */
444 modest_mail_operation_send_mail (ModestMailOperation *self,
445 TnyTransportAccount *transport_account,
448 TnySendQueue *send_queue;
450 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
451 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
452 g_return_if_fail (TNY_IS_MSG (msg));
454 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
455 if (!TNY_IS_SEND_QUEUE(send_queue))
456 g_printerr ("modest: could not find send queue for account\n");
459 tny_send_queue_add (send_queue, msg, &err);
461 g_printerr ("modest: error adding msg to send queue: %s\n",
465 /* g_message ("modest: message added to send queue"); */
469 /* Notify about operation end */
470 modest_mail_operation_notify_end (self);
474 modest_mail_operation_send_new_mail (ModestMailOperation *self,
475 TnyTransportAccount *transport_account,
476 const gchar *from, const gchar *to,
477 const gchar *cc, const gchar *bcc,
478 const gchar *subject, const gchar *plain_body,
479 const gchar *html_body,
480 const GList *attachments_list,
481 TnyHeaderFlags priority_flags)
484 ModestMailOperationPrivate *priv = NULL;
485 /* GList *node = NULL; */
487 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
488 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
492 /* Check parametters */
494 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
495 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
496 _("Error trying to send a mail. You need to set at least one recipient"));
500 if (html_body == NULL) {
501 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
503 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
506 g_printerr ("modest: failed to create a new msg\n");
510 /* TODO: add priority handling. It's received in the priority_flags operator, and
511 it should have effect in the sending operation */
513 /* Call mail operation */
514 modest_mail_operation_send_mail (self, transport_account, new_msg);
517 g_object_unref (G_OBJECT (new_msg));
521 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
522 TnyTransportAccount *transport_account,
523 const gchar *from, const gchar *to,
524 const gchar *cc, const gchar *bcc,
525 const gchar *subject, const gchar *plain_body,
526 const gchar *html_body,
527 const GList *attachments_list,
528 TnyHeaderFlags priority_flags)
531 TnyFolder *folder = NULL;
532 ModestMailOperationPrivate *priv = NULL;
535 /* GList *node = NULL; */
537 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
538 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
542 if (html_body == NULL) {
543 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
545 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
548 g_printerr ("modest: failed to create a new msg\n");
552 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
554 g_printerr ("modest: failed to find Drafts folder\n");
558 tny_folder_add_msg (folder, msg, &err);
560 g_printerr ("modest: error adding msg to Drafts folder: %s",
566 modest_mail_operation_notify_end (self);
571 g_object_unref (G_OBJECT(msg));
573 g_object_unref (G_OBJECT(folder));
578 ModestMailOperation *mail_op;
579 TnyStoreAccount *account;
580 TnyTransportAccount *transport_account;
583 gchar *retrieve_type;
586 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
587 /* We use this folder observer to track the headers that have been
588 * added to a folder */
591 TnyList *new_headers;
592 } InternalFolderObserver;
596 } InternalFolderObserverClass;
598 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
600 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
601 internal_folder_observer,
603 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
607 foreach_add_item (gpointer header, gpointer user_data)
609 tny_list_prepend (TNY_LIST (user_data),
610 g_object_ref (G_OBJECT (header)));
613 /* This is the method that looks for new messages in a folder */
615 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
617 TnyFolderChangeChanged changed;
619 changed = tny_folder_change_get_changed (change);
621 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
624 /* Get added headers */
625 list = tny_simple_list_new ();
626 tny_folder_change_get_added_headers (change, list);
628 /* Add them to the folder observer */
629 tny_list_foreach (list, foreach_add_item,
630 ((InternalFolderObserver *)self)->new_headers);
632 g_object_unref (G_OBJECT (list));
637 internal_folder_observer_init (InternalFolderObserver *self)
639 self->new_headers = tny_simple_list_new ();
642 internal_folder_observer_finalize (GObject *object)
644 InternalFolderObserver *self;
646 self = (InternalFolderObserver *) object;
647 g_object_unref (self->new_headers);
649 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
652 tny_folder_observer_init (TnyFolderObserverIface *iface)
654 iface->update_func = internal_folder_observer_update;
657 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
659 GObjectClass *object_class;
661 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
662 object_class = (GObjectClass*) klass;
663 object_class->finalize = internal_folder_observer_finalize;
669 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
672 TnyList *folders = tny_simple_list_new ();
674 tny_folder_store_get_folders (store, folders, query, NULL);
675 iter = tny_list_create_iterator (folders);
677 while (!tny_iterator_is_done (iter)) {
679 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
681 tny_list_prepend (all_folders, G_OBJECT (folder));
682 recurse_folders (folder, query, all_folders);
683 g_object_unref (G_OBJECT (folder));
685 tny_iterator_next (iter);
687 g_object_unref (G_OBJECT (iter));
688 g_object_unref (G_OBJECT (folders));
692 * Issues the "progress-changed" signal. The timer won't be removed,
693 * so you must call g_source_remove to stop the signal emission
696 idle_notify_progress (gpointer data)
698 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
699 ModestMailOperationState *state;
701 state = modest_mail_operation_clone_state (mail_op);
702 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
703 g_slice_free (ModestMailOperationState, state);
709 * Issues the "progress-changed" signal and removes the timer. It uses
710 * a lock to ensure that the progress information of the mail
711 * operation is not modified while there are notifications pending
714 idle_notify_progress_once (gpointer data)
718 pair = (ModestPair *) data;
720 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
722 /* Free the state and the reference to the mail operation */
723 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
724 g_object_unref (pair->first);
730 * Used by update_account_thread to notify the queue from the main
731 * loop. We call it inside an idle call to achieve that
734 notify_update_account_queue (gpointer data)
736 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
738 modest_mail_operation_notify_end (mail_op);
739 g_object_unref (mail_op);
745 update_account_thread (gpointer thr_user_data)
747 UpdateAccountInfo *info;
748 TnyList *all_folders = NULL, *new_headers;
749 TnyIterator *iter = NULL;
750 TnyFolderStoreQuery *query = NULL;
751 ModestMailOperationPrivate *priv;
752 ModestTnySendQueue *send_queue;
753 gint timeout, msg_num;
755 info = (UpdateAccountInfo *) thr_user_data;
756 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
758 /* Get all the folders We can do it synchronously because
759 we're already running in a different thread than the UI */
760 all_folders = tny_simple_list_new ();
761 query = tny_folder_store_query_new ();
762 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
763 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
768 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
772 iter = tny_list_create_iterator (all_folders);
773 while (!tny_iterator_is_done (iter)) {
774 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
776 recurse_folders (folder, query, all_folders);
777 tny_iterator_next (iter);
779 g_object_unref (G_OBJECT (iter));
781 /* Update status and notify. We need to call the notification
782 with a source functopm in order to call it from the main
783 loop. We need that in order not to get into trouble with
784 Gtk+. We use a timeout in order to provide more status
785 information, because the sync tinymail call does not
786 provide it for the moment */
787 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
789 /* Refresh folders */
790 new_headers = tny_simple_list_new ();
791 iter = tny_list_create_iterator (all_folders);
792 while (!tny_iterator_is_done (iter) && !priv->error) {
794 InternalFolderObserver *observer;
795 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
797 /* Refresh the folder */
798 observer = g_object_new (internal_folder_observer_get_type (), NULL);
799 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
800 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
802 /* If the retrieve type is headers only do nothing more */
803 if (!strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
804 !strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
807 iter = tny_list_create_iterator (observer->new_headers);
808 while (!tny_iterator_is_done (iter)) {
809 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
810 /* Apply per-message size limits */
811 if (tny_header_get_message_size (header) < info->max_size)
812 tny_list_prepend (new_headers, G_OBJECT (header));
814 g_object_unref (header);
815 tny_iterator_next (iter);
817 g_object_unref (iter);
819 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
820 g_object_unref (observer);
823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 g_object_unref (G_OBJECT (folder));
826 tny_iterator_next (iter);
828 g_object_unref (G_OBJECT (iter));
829 g_source_remove (timeout);
832 /* Apply message count limit */
833 /* TODO if the number of messages exceeds the maximum, ask the
834 user to download them all */
836 priv->total = MIN (tny_list_get_length (new_headers), info->retrieve_limit);
837 iter = tny_list_create_iterator (new_headers);
838 while ((msg_num < info->retrieve_limit) && !tny_iterator_is_done (iter)) {
840 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
841 TnyFolder *folder = tny_header_get_folder (header);
842 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
843 ModestMailOperationState *state;
847 /* We can not just use the mail operation because the
848 values of done and total could change before the
850 state = modest_mail_operation_clone_state (info->mail_op);
851 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
852 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
853 pair, (GDestroyNotify) modest_pair_free);
855 g_object_unref (msg);
856 g_object_unref (folder);
857 g_object_unref (header);
860 tny_iterator_next (iter);
862 g_object_unref (iter);
863 g_object_unref (new_headers);
866 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
870 send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
872 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
873 modest_tny_send_queue_flush (send_queue);
874 g_source_remove (timeout);
876 g_object_unref (G_OBJECT(send_queue));
878 /* Check if the operation was a success */
880 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
882 /* Update the last updated key */
883 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
884 tny_account_get_id (TNY_ACCOUNT (info->account)),
885 MODEST_ACCOUNT_LAST_UPDATED,
891 /* Notify about operation end. Note that the info could be
892 freed before this idle happens, but the mail operation will
894 g_idle_add (notify_update_account_queue, info->mail_op);
897 g_object_unref (query);
898 g_object_unref (all_folders);
899 g_object_unref (info->account);
900 g_object_unref (info->transport_account);
901 g_free (info->retrieve_type);
902 g_slice_free (UpdateAccountInfo, info);
908 modest_mail_operation_update_account (ModestMailOperation *self,
909 const gchar *account_name)
912 UpdateAccountInfo *info;
913 ModestMailOperationPrivate *priv;
914 ModestAccountMgr *mgr;
915 TnyStoreAccount *modest_account;
916 TnyTransportAccount *transport_account;
918 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
919 g_return_val_if_fail (account_name, FALSE);
921 /* Init mail operation. Set total and done to 0, and do not
922 update them, this way the progress objects will know that
923 we have no clue about the number of the objects */
924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
927 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
929 /* Get the Modest account */
930 modest_account = (TnyStoreAccount *)
931 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
933 TNY_ACCOUNT_TYPE_STORE);
935 if (!modest_account) {
936 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
937 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
938 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
939 "cannot get tny store account for %s\n", account_name);
940 modest_mail_operation_notify_end (self);
944 /* Get the transport account, we can not do it in the thread
945 due to some problems with dbus */
946 transport_account = (TnyTransportAccount *)
947 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
949 if (!transport_account) {
950 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
951 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
952 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
953 "cannot get tny transport account for %s\n", account_name);
954 modest_mail_operation_notify_end (self);
958 /* Create the helper object */
959 info = g_slice_new (UpdateAccountInfo);
960 info->mail_op = self;
961 info->account = modest_account;
962 info->transport_account = transport_account;
964 /* Get the message size limit */
965 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
966 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
967 if (info->max_size == 0)
968 info->max_size = G_MAXINT;
970 info->max_size = info->max_size * KB;
972 /* Get per-account retrieval type */
973 mgr = modest_runtime_get_account_mgr ();
974 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
975 MODEST_ACCOUNT_RETRIEVE, FALSE);
977 /* Get per-account message amount retrieval limit */
978 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
979 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
980 if (info->retrieve_limit == 0)
981 info->retrieve_limit = G_MAXINT;
983 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
988 /* ******************************************************************* */
989 /* ************************** STORE ACTIONS ************************* */
990 /* ******************************************************************* */
994 modest_mail_operation_create_folder (ModestMailOperation *self,
995 TnyFolderStore *parent,
998 ModestTnyFolderRules rules;
999 ModestMailOperationPrivate *priv;
1000 TnyFolder *new_folder = NULL;
1001 gboolean can_create = FALSE;
1003 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1004 g_return_val_if_fail (name, NULL);
1006 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1009 if (!TNY_IS_FOLDER (parent)) {
1010 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1011 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1012 _("mail_in_ui_folder_create_error"));
1014 /* Check folder rules */
1015 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1016 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
1017 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1018 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1019 _("mail_in_ui_folder_create_error"));
1025 /* Create the folder */
1026 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1027 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1030 /* Notify about operation end */
1031 modest_mail_operation_notify_end (self);
1037 modest_mail_operation_remove_folder (ModestMailOperation *self,
1039 gboolean remove_to_trash)
1041 TnyAccount *account;
1042 ModestMailOperationPrivate *priv;
1043 ModestTnyFolderRules rules;
1045 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1046 g_return_if_fail (TNY_IS_FOLDER (folder));
1048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1050 /* Check folder rules */
1051 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1052 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1054 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1055 _("mail_in_ui_folder_delete_error"));
1059 /* Get the account */
1060 account = tny_folder_get_account (folder);
1062 /* Delete folder or move to trash */
1063 if (remove_to_trash) {
1064 TnyFolder *trash_folder = NULL;
1065 trash_folder = modest_tny_account_get_special_folder (account,
1066 TNY_FOLDER_TYPE_TRASH);
1067 /* TODO: error_handling */
1068 modest_mail_operation_xfer_folder (self, folder,
1069 TNY_FOLDER_STORE (trash_folder), TRUE);
1071 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1073 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1074 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1077 g_object_unref (G_OBJECT (parent));
1079 g_object_unref (G_OBJECT (account));
1082 /* Notify about operation end */
1083 modest_mail_operation_notify_end (self);
1087 modest_mail_operation_rename_folder (ModestMailOperation *self,
1091 ModestMailOperationPrivate *priv;
1092 ModestTnyFolderRules rules;
1094 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1095 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1096 g_return_if_fail (name);
1098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1100 /* Check folder rules */
1101 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1102 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1103 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1104 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1105 _("FIXME: unable to rename"));
1107 /* Rename. Camel handles folder subscription/unsubscription */
1108 TnyFolderStore *into;
1111 into = tny_folder_get_folder_store (folder);
1112 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
1114 g_object_unref (into);
1116 g_object_unref (nfol);
1118 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1122 /* Notify about operation end */
1123 modest_mail_operation_notify_end (self);
1127 transfer_folder_status_cb (GObject *obj,
1131 XFerMsgAsyncHelper *helper = NULL;
1132 ModestMailOperation *self;
1133 ModestMailOperationPrivate *priv;
1134 ModestMailOperationState *state;
1136 g_return_if_fail (status != NULL);
1137 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1139 helper = (XFerMsgAsyncHelper *) user_data;
1140 g_return_if_fail (helper != NULL);
1142 self = helper->mail_op;
1143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1145 if ((status->position == 1) && (status->of_total == 100))
1148 priv->done = status->position;
1149 priv->total = status->of_total;
1151 state = modest_mail_operation_clone_state (self);
1152 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1153 g_slice_free (ModestMailOperationState, state);
1158 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
1160 XFerFolderAsyncHelper *helper = NULL;
1161 ModestMailOperation *self = NULL;
1162 ModestMailOperationPrivate *priv = NULL;
1164 helper = (XFerFolderAsyncHelper *) user_data;
1165 self = helper->mail_op;
1167 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1170 priv->error = g_error_copy (*err);
1172 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1173 } else if (cancelled) {
1174 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1175 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1176 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1177 _("Transference of %s was cancelled."),
1178 tny_folder_get_name (folder));
1181 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1185 g_slice_free (XFerFolderAsyncHelper, helper);
1186 g_object_unref (folder);
1187 g_object_unref (into);
1188 if (new_folder != NULL)
1189 g_object_unref (new_folder);
1191 /* Notify about operation end */
1192 modest_mail_operation_notify_end (self);
1196 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1198 TnyFolderStore *parent,
1199 gboolean delete_original)
1201 XFerFolderAsyncHelper *helper = NULL;
1202 ModestMailOperationPrivate *priv = NULL;
1203 ModestTnyFolderRules parent_rules, rules;
1205 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1206 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1207 g_return_if_fail (TNY_IS_FOLDER (folder));
1209 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1211 /* Pick references for async calls */
1212 g_object_ref (folder);
1213 g_object_ref (parent);
1215 /* Get folder rules */
1216 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1217 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1219 /* The moveable restriction is applied also to copy operation */
1220 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
1221 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1222 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1223 _("mail_in_ui_folder_move_target_error"));
1225 /* Notify the queue */
1226 modest_mail_operation_notify_end (self);
1227 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1229 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1230 _("FIXME: parent folder does not accept new folders"));
1232 /* Notify the queue */
1233 modest_mail_operation_notify_end (self);
1235 helper = g_slice_new0 (XFerFolderAsyncHelper);
1236 helper->mail_op = self;
1238 /* Move/Copy folder */
1239 tny_folder_copy_async (folder,
1241 tny_folder_get_name (folder),
1244 transfer_folder_status_cb,
1250 /* ******************************************************************* */
1251 /* ************************** MSG ACTIONS ************************* */
1252 /* ******************************************************************* */
1254 void modest_mail_operation_get_msg (ModestMailOperation *self,
1256 GetMsgAsyncUserCallback user_callback,
1259 GetMsgAsyncHelper *helper = NULL;
1261 ModestMailOperationPrivate *priv;
1263 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1264 g_return_if_fail (TNY_IS_HEADER (header));
1266 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1267 folder = tny_header_get_folder (header);
1269 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1271 /* Get message from folder */
1273 helper = g_slice_new0 (GetMsgAsyncHelper);
1274 helper->mail_op = self;
1275 helper->user_callback = user_callback;
1276 helper->pending_ops = 1;
1277 helper->user_data = user_data;
1279 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1281 g_object_unref (G_OBJECT (folder));
1283 /* Set status failed and set an error */
1284 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1285 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1286 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1287 _("Error trying to get a message. No folder found for header"));
1292 get_msg_cb (TnyFolder *folder,
1298 GetMsgAsyncHelper *helper = NULL;
1299 ModestMailOperation *self = NULL;
1300 ModestMailOperationPrivate *priv = NULL;
1302 helper = (GetMsgAsyncHelper *) user_data;
1303 g_return_if_fail (helper != NULL);
1304 self = helper->mail_op;
1305 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1308 helper->pending_ops--;
1310 /* Check errors and cancel */
1312 priv->error = g_error_copy (*error);
1313 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1317 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1318 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1319 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1320 _("Error trying to refresh the contents of %s"),
1321 tny_folder_get_name (folder));
1325 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1327 /* If user defined callback function was defined, call it */
1328 if (helper->user_callback) {
1329 helper->user_callback (self, NULL, msg, helper->user_data);
1334 if (helper->pending_ops == 0) {
1335 g_slice_free (GetMsgAsyncHelper, helper);
1337 /* Notify about operation end */
1338 modest_mail_operation_notify_end (self);
1343 get_msg_status_cb (GObject *obj,
1347 GetMsgAsyncHelper *helper = NULL;
1348 ModestMailOperation *self;
1349 ModestMailOperationPrivate *priv;
1350 ModestMailOperationState *state;
1352 g_return_if_fail (status != NULL);
1353 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1355 helper = (GetMsgAsyncHelper *) user_data;
1356 g_return_if_fail (helper != NULL);
1358 self = helper->mail_op;
1359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1361 if ((status->position == 1) && (status->of_total == 100))
1367 state = modest_mail_operation_clone_state (self);
1368 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1369 g_slice_free (ModestMailOperationState, state);
1372 /****************************************************/
1374 ModestMailOperation *mail_op;
1376 GetMsgAsyncUserCallback user_callback;
1378 GDestroyNotify notify;
1382 GetMsgAsyncUserCallback user_callback;
1386 ModestMailOperation *mail_op;
1387 } NotifyGetMsgsInfo;
1391 * Used by get_msgs_full_thread to call the user_callback for each
1392 * message that has been read
1395 notify_get_msgs_full (gpointer data)
1397 NotifyGetMsgsInfo *info;
1399 info = (NotifyGetMsgsInfo *) data;
1401 /* Call the user callback */
1402 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1404 g_slice_free (NotifyGetMsgsInfo, info);
1410 * Used by get_msgs_full_thread to free al the thread resources and to
1411 * call the destroy function for the passed user_data
1414 get_msgs_full_destroyer (gpointer data)
1416 GetFullMsgsInfo *info;
1418 info = (GetFullMsgsInfo *) data;
1421 info->notify (info->user_data);
1424 g_object_unref (info->headers);
1425 g_slice_free (GetFullMsgsInfo, info);
1431 get_msgs_full_thread (gpointer thr_user_data)
1433 GetFullMsgsInfo *info;
1434 ModestMailOperationPrivate *priv = NULL;
1435 TnyIterator *iter = NULL;
1437 info = (GetFullMsgsInfo *) thr_user_data;
1438 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1440 iter = tny_list_create_iterator (info->headers);
1441 while (!tny_iterator_is_done (iter)) {
1445 header = TNY_HEADER (tny_iterator_get_current (iter));
1446 folder = tny_header_get_folder (header);
1448 /* Get message from folder */
1451 /* The callback will call it per each header */
1452 msg = tny_folder_get_msg (folder, header, &(priv->error));
1455 ModestMailOperationState *state;
1460 /* notify progress */
1461 state = modest_mail_operation_clone_state (info->mail_op);
1462 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1463 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1464 pair, (GDestroyNotify) modest_pair_free);
1466 /* The callback is the responsible for
1467 freeing the message */
1468 if (info->user_callback) {
1469 NotifyGetMsgsInfo *info_notify;
1470 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1471 info_notify->user_callback = info->user_callback;
1472 info_notify->mail_op = info->mail_op;
1473 info_notify->header = g_object_ref (header);
1474 info_notify->msg = g_object_ref (msg);
1475 info_notify->user_data = info->user_data;
1476 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1477 notify_get_msgs_full,
1480 g_object_unref (msg);
1483 /* Set status failed and set an error */
1484 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1485 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1486 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1487 "Error trying to get a message. No folder found for header");
1489 g_object_unref (header);
1490 tny_iterator_next (iter);
1493 /* Notify about operation end */
1494 g_idle_add (notify_update_account_queue, info->mail_op);
1496 /* Free thread resources. Will be called after all previous idles */
1497 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1503 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1504 TnyList *header_list,
1505 GetMsgAsyncUserCallback user_callback,
1507 GDestroyNotify notify)
1510 ModestMailOperationPrivate *priv = NULL;
1511 GetFullMsgsInfo *info = NULL;
1512 gboolean size_ok = TRUE;
1514 GError *error = NULL;
1516 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1518 /* Init mail operation */
1519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1520 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1522 priv->total = tny_list_get_length(header_list);
1524 /* Get msg size limit */
1525 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1526 MODEST_CONF_MSG_SIZE_LIMIT,
1529 g_clear_error (&error);
1530 max_size = G_MAXINT;
1532 max_size = max_size * KB;
1535 /* Check message size limits. If there is only one message
1536 always retrieve it */
1537 if (tny_list_get_length (header_list) > 1) {
1540 iter = tny_list_create_iterator (header_list);
1541 while (!tny_iterator_is_done (iter) && size_ok) {
1542 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1543 if (tny_header_get_message_size (header) >= max_size)
1545 g_object_unref (header);
1546 tny_iterator_next (iter);
1548 g_object_unref (iter);
1552 /* Create the info */
1553 info = g_slice_new0 (GetFullMsgsInfo);
1554 info->mail_op = self;
1555 info->user_callback = user_callback;
1556 info->user_data = user_data;
1557 info->headers = g_object_ref (header_list);
1558 info->notify = notify;
1560 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1562 /* FIXME: the error msg is different for pop */
1563 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1564 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1565 _("emev_ni_ui_imap_msg_sizelimit_error"));
1566 /* Remove from queue and free resources */
1567 modest_mail_operation_notify_end (self);
1575 modest_mail_operation_remove_msg (ModestMailOperation *self,
1577 gboolean remove_to_trash)
1580 ModestMailOperationPrivate *priv;
1582 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1583 g_return_if_fail (TNY_IS_HEADER (header));
1585 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1586 folder = tny_header_get_folder (header);
1588 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1590 /* Delete or move to trash */
1591 if (remove_to_trash) {
1592 TnyFolder *trash_folder;
1593 TnyStoreAccount *store_account;
1595 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1596 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1597 TNY_FOLDER_TYPE_TRASH);
1602 headers = tny_simple_list_new ();
1603 tny_list_append (headers, G_OBJECT (header));
1604 g_object_unref (header);
1607 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1608 g_object_unref (headers);
1609 /* g_object_unref (trash_folder); */
1611 ModestMailOperationPrivate *priv;
1613 /* Set status failed and set an error */
1614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1615 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1616 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1617 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1618 _("Error trying to delete a message. Trash folder not found"));
1621 g_object_unref (G_OBJECT (store_account));
1623 tny_folder_remove_msg (folder, header, &(priv->error));
1625 tny_folder_sync(folder, TRUE, &(priv->error));
1630 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1632 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1635 g_object_unref (G_OBJECT (folder));
1637 /* Notify about operation end */
1638 modest_mail_operation_notify_end (self);
1642 transfer_msgs_status_cb (GObject *obj,
1646 XFerMsgAsyncHelper *helper = NULL;
1647 ModestMailOperation *self;
1648 ModestMailOperationPrivate *priv;
1649 ModestMailOperationState *state;
1652 g_return_if_fail (status != NULL);
1653 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1655 helper = (XFerMsgAsyncHelper *) user_data;
1656 g_return_if_fail (helper != NULL);
1658 self = helper->mail_op;
1659 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1661 if ((status->position == 1) && (status->of_total == 100))
1664 priv->done = status->position;
1665 priv->total = status->of_total;
1667 state = modest_mail_operation_clone_state (self);
1668 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1669 g_slice_free (ModestMailOperationState, state);
1674 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1676 XFerMsgAsyncHelper *helper;
1677 ModestMailOperation *self;
1678 ModestMailOperationPrivate *priv;
1680 helper = (XFerMsgAsyncHelper *) user_data;
1681 self = helper->mail_op;
1683 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1686 priv->error = g_error_copy (*err);
1688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1689 } else if (cancelled) {
1690 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1692 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1693 _("Error trying to refresh the contents of %s"),
1694 tny_folder_get_name (folder));
1697 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1700 /* If user defined callback function was defined, call it */
1701 if (helper->user_callback) {
1702 helper->user_callback (priv->source, helper->user_data);
1706 g_object_unref (helper->headers);
1707 g_object_unref (helper->dest_folder);
1708 g_object_unref (helper->mail_op);
1709 g_slice_free (XFerMsgAsyncHelper, helper);
1710 g_object_unref (folder);
1712 /* Notify about operation end */
1713 modest_mail_operation_notify_end (self);
1717 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1720 gboolean delete_original,
1721 XferMsgsAsynUserCallback user_callback,
1724 ModestMailOperationPrivate *priv;
1726 TnyFolder *src_folder;
1727 XFerMsgAsyncHelper *helper;
1729 ModestTnyFolderRules rules;
1731 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1732 g_return_if_fail (TNY_IS_LIST (headers));
1733 g_return_if_fail (TNY_IS_FOLDER (folder));
1735 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1738 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1740 /* Apply folder rules */
1741 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1743 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1744 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1745 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1746 _("FIXME: folder does not accept msgs"));
1747 /* Notify the queue */
1748 modest_mail_operation_notify_end (self);
1752 /* Create the helper */
1753 helper = g_slice_new0 (XFerMsgAsyncHelper);
1754 helper->mail_op = g_object_ref(self);
1755 helper->dest_folder = g_object_ref(folder);
1756 helper->headers = g_object_ref(headers);
1757 helper->user_callback = user_callback;
1758 helper->user_data = user_data;
1760 /* Get source folder */
1761 iter = tny_list_create_iterator (headers);
1762 header = TNY_HEADER (tny_iterator_get_current (iter));
1763 src_folder = tny_header_get_folder (header);
1764 g_object_unref (header);
1765 g_object_unref (iter);
1767 /* Transfer messages */
1768 tny_folder_transfer_msgs_async (src_folder,
1773 transfer_msgs_status_cb,
1779 on_refresh_folder (TnyFolder *folder,
1784 ModestMailOperation *self;
1785 ModestMailOperationPrivate *priv;
1787 self = MODEST_MAIL_OPERATION (user_data);
1788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1791 priv->error = g_error_copy (*error);
1792 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1797 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1798 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1799 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1800 _("Error trying to refresh the contents of %s"),
1801 tny_folder_get_name (folder));
1805 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1809 g_object_unref (folder);
1811 /* Notify about operation end */
1812 modest_mail_operation_notify_end (self);
1816 on_refresh_folder_status_update (GObject *obj,
1820 ModestMailOperation *self;
1821 ModestMailOperationPrivate *priv;
1822 ModestMailOperationState *state;
1824 g_return_if_fail (status != NULL);
1825 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1827 self = MODEST_MAIL_OPERATION (user_data);
1828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1830 priv->done = status->position;
1831 priv->total = status->of_total;
1833 state = modest_mail_operation_clone_state (self);
1834 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1835 g_slice_free (ModestMailOperationState, state);
1839 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1842 ModestMailOperationPrivate *priv;
1844 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1846 /* Pick a reference */
1847 g_object_ref (folder);
1849 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1851 /* Refresh the folder. TODO: tinymail could issue a status
1852 updates before the callback call then this could happen. We
1853 must review the design */
1854 tny_folder_refresh_async (folder,
1856 on_refresh_folder_status_update,
1862 * It's used by the mail operation queue to notify the observers
1863 * attached to that signal that the operation finished. We need to use
1864 * that because tinymail does not give us the progress of a given
1865 * operation when it finishes (it directly calls the operation
1869 modest_mail_operation_notify_end (ModestMailOperation *self)
1871 ModestMailOperationState *state;
1873 /* Notify the observers about the mail opertation end */
1874 state = modest_mail_operation_clone_state (self);
1875 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1876 g_slice_free (ModestMailOperationState, state);
1878 /* Notify the queue */
1879 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);