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 compare_headers_by_date (gconstpointer a,
748 TnyHeader **header1, **header2;
751 header1 = (TnyHeader **) a;
752 header2 = (TnyHeader **) b;
754 sent1 = tny_header_get_date_sent (*header1);
755 sent2 = tny_header_get_date_sent (*header2);
757 /* We want the most recent ones (greater time_t) at the
766 update_account_thread (gpointer thr_user_data)
768 UpdateAccountInfo *info;
769 TnyList *all_folders = NULL;
770 GPtrArray *new_headers;
771 TnyIterator *iter = NULL;
772 TnyFolderStoreQuery *query = NULL;
773 ModestMailOperationPrivate *priv;
775 info = (UpdateAccountInfo *) thr_user_data;
776 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
778 /* Get all the folders We can do it synchronously because
779 we're already running in a different thread than the UI */
780 all_folders = tny_simple_list_new ();
781 query = tny_folder_store_query_new ();
782 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
783 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
788 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
792 iter = tny_list_create_iterator (all_folders);
793 while (!tny_iterator_is_done (iter)) {
794 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
796 recurse_folders (folder, query, all_folders);
797 tny_iterator_next (iter);
799 g_object_unref (G_OBJECT (iter));
801 /* Update status and notify. We need to call the notification
802 with a source functopm in order to call it from the main
803 loop. We need that in order not to get into trouble with
804 Gtk+. We use a timeout in order to provide more status
805 information, because the sync tinymail call does not
806 provide it for the moment */
807 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
809 /* Refresh folders */
810 new_headers = g_ptr_array_new ();
811 iter = tny_list_create_iterator (all_folders);
812 while (!tny_iterator_is_done (iter) && !priv->error) {
814 InternalFolderObserver *observer;
815 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
817 /* Refresh the folder */
818 observer = g_object_new (internal_folder_observer_get_type (), NULL);
819 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
820 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
822 /* If the retrieve type is headers only do nothing more */
823 if (!strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
824 !strcmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
827 iter = tny_list_create_iterator (observer->new_headers);
828 while (!tny_iterator_is_done (iter)) {
829 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
830 /* Apply per-message size limits */
831 if (tny_header_get_message_size (header) < info->max_size)
832 g_ptr_array_add (new_headers, g_object_ref (header));
834 g_object_unref (header);
835 tny_iterator_next (iter);
837 g_object_unref (iter);
839 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
840 g_object_unref (observer);
843 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
845 g_object_unref (G_OBJECT (folder));
846 tny_iterator_next (iter);
848 g_object_unref (G_OBJECT (iter));
849 g_source_remove (timeout);
851 if (new_headers->len > 0) {
855 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
857 /* Apply message count limit */
858 /* TODO if the number of messages exceeds the maximum, ask the
859 user to download them all */
861 priv->total = MIN (new_headers->len, info->retrieve_limit);
862 while ((msg_num < info->retrieve_limit)) {
864 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
865 TnyFolder *folder = tny_header_get_folder (header);
866 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
867 ModestMailOperationState *state;
871 /* We can not just use the mail operation because the
872 values of done and total could change before the
874 state = modest_mail_operation_clone_state (info->mail_op);
875 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
876 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
877 pair, (GDestroyNotify) modest_pair_free);
879 g_object_unref (msg);
880 g_object_unref (folder);
884 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
885 g_ptr_array_free (new_headers, FALSE);
889 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
893 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
894 (info->transport_account);
896 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
897 /* TODO: Is this meant to block? */
898 modest_tny_send_queue_try_to_send (send_queue);
899 g_source_remove (timeout);
901 g_object_unref (G_OBJECT(send_queue));
903 /* Check if the operation was a success */
905 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
907 /* Update the last updated key */
908 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
909 tny_account_get_id (TNY_ACCOUNT (info->account)),
910 MODEST_ACCOUNT_LAST_UPDATED,
916 /* Notify about operation end. Note that the info could be
917 freed before this idle happens, but the mail operation will
919 g_idle_add (notify_update_account_queue, info->mail_op);
922 g_object_unref (query);
923 g_object_unref (all_folders);
924 g_object_unref (info->account);
925 g_object_unref (info->transport_account);
926 g_free (info->retrieve_type);
927 g_slice_free (UpdateAccountInfo, info);
933 modest_mail_operation_update_account (ModestMailOperation *self,
934 const gchar *account_name)
937 UpdateAccountInfo *info;
938 ModestMailOperationPrivate *priv;
939 ModestAccountMgr *mgr;
940 TnyStoreAccount *modest_account;
941 TnyTransportAccount *transport_account;
943 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
944 g_return_val_if_fail (account_name, FALSE);
946 /* Init mail operation. Set total and done to 0, and do not
947 update them, this way the progress objects will know that
948 we have no clue about the number of the objects */
949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
952 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
954 /* Get the Modest account */
955 modest_account = (TnyStoreAccount *)
956 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
958 TNY_ACCOUNT_TYPE_STORE);
960 if (!modest_account) {
961 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
962 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
963 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
964 "cannot get tny store account for %s\n", account_name);
965 modest_mail_operation_notify_end (self);
969 /* Get the transport account, we can not do it in the thread
970 due to some problems with dbus */
971 transport_account = (TnyTransportAccount *)
972 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
974 if (!transport_account) {
975 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
976 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
977 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
978 "cannot get tny transport account for %s\n", account_name);
979 modest_mail_operation_notify_end (self);
983 /* Create the helper object */
984 info = g_slice_new (UpdateAccountInfo);
985 info->mail_op = self;
986 info->account = modest_account;
987 info->transport_account = transport_account;
989 /* Get the message size limit */
990 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
991 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
992 if (info->max_size == 0)
993 info->max_size = G_MAXINT;
995 info->max_size = info->max_size * KB;
997 /* Get per-account retrieval type */
998 mgr = modest_runtime_get_account_mgr ();
999 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1000 MODEST_ACCOUNT_RETRIEVE, FALSE);
1002 /* Get per-account message amount retrieval limit */
1003 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1004 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1005 if (info->retrieve_limit == 0)
1006 info->retrieve_limit = G_MAXINT;
1008 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1013 /* ******************************************************************* */
1014 /* ************************** STORE ACTIONS ************************* */
1015 /* ******************************************************************* */
1019 modest_mail_operation_create_folder (ModestMailOperation *self,
1020 TnyFolderStore *parent,
1023 ModestTnyFolderRules rules;
1024 ModestMailOperationPrivate *priv;
1025 TnyFolder *new_folder = NULL;
1026 gboolean can_create = FALSE;
1028 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1029 g_return_val_if_fail (name, NULL);
1031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1034 if (!TNY_IS_FOLDER (parent)) {
1035 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1036 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1037 _("mail_in_ui_folder_create_error"));
1039 /* Check folder rules */
1040 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1041 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
1042 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1043 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1044 _("mail_in_ui_folder_create_error"));
1050 /* Create the folder */
1051 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1052 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1055 /* Notify about operation end */
1056 modest_mail_operation_notify_end (self);
1062 modest_mail_operation_remove_folder (ModestMailOperation *self,
1064 gboolean remove_to_trash)
1066 TnyAccount *account;
1067 ModestMailOperationPrivate *priv;
1068 ModestTnyFolderRules rules;
1070 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1071 g_return_if_fail (TNY_IS_FOLDER (folder));
1073 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1075 /* Check folder rules */
1076 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1077 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1078 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1079 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1080 _("mail_in_ui_folder_delete_error"));
1084 /* Get the account */
1085 account = tny_folder_get_account (folder);
1087 /* Delete folder or move to trash */
1088 if (remove_to_trash) {
1089 TnyFolder *trash_folder = NULL;
1090 trash_folder = modest_tny_account_get_special_folder (account,
1091 TNY_FOLDER_TYPE_TRASH);
1092 /* TODO: error_handling */
1093 modest_mail_operation_xfer_folder (self, folder,
1094 TNY_FOLDER_STORE (trash_folder), TRUE);
1096 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1098 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1099 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1102 g_object_unref (G_OBJECT (parent));
1104 g_object_unref (G_OBJECT (account));
1107 /* Notify about operation end */
1108 modest_mail_operation_notify_end (self);
1112 modest_mail_operation_rename_folder (ModestMailOperation *self,
1116 ModestMailOperationPrivate *priv;
1117 ModestTnyFolderRules rules;
1119 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1120 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1121 g_return_if_fail (name);
1123 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1125 /* Check folder rules */
1126 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1127 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1128 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1129 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1130 _("FIXME: unable to rename"));
1132 /* Rename. Camel handles folder subscription/unsubscription */
1133 TnyFolderStore *into;
1136 into = tny_folder_get_folder_store (folder);
1137 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
1139 g_object_unref (into);
1141 g_object_unref (nfol);
1143 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1147 /* Notify about operation end */
1148 modest_mail_operation_notify_end (self);
1152 transfer_folder_status_cb (GObject *obj,
1156 XFerMsgAsyncHelper *helper = NULL;
1157 ModestMailOperation *self;
1158 ModestMailOperationPrivate *priv;
1159 ModestMailOperationState *state;
1161 g_return_if_fail (status != NULL);
1162 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1164 helper = (XFerMsgAsyncHelper *) user_data;
1165 g_return_if_fail (helper != NULL);
1167 self = helper->mail_op;
1168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1170 if ((status->position == 1) && (status->of_total == 100))
1173 priv->done = status->position;
1174 priv->total = status->of_total;
1176 state = modest_mail_operation_clone_state (self);
1177 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1178 g_slice_free (ModestMailOperationState, state);
1183 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
1185 XFerFolderAsyncHelper *helper = NULL;
1186 ModestMailOperation *self = NULL;
1187 ModestMailOperationPrivate *priv = NULL;
1189 helper = (XFerFolderAsyncHelper *) user_data;
1190 self = helper->mail_op;
1192 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1195 priv->error = g_error_copy (*err);
1197 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1198 } else if (cancelled) {
1199 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1200 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1201 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1202 _("Transference of %s was cancelled."),
1203 tny_folder_get_name (folder));
1206 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1210 g_slice_free (XFerFolderAsyncHelper, helper);
1211 g_object_unref (folder);
1212 g_object_unref (into);
1213 if (new_folder != NULL)
1214 g_object_unref (new_folder);
1216 /* Notify about operation end */
1217 modest_mail_operation_notify_end (self);
1221 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1223 TnyFolderStore *parent,
1224 gboolean delete_original)
1226 XFerFolderAsyncHelper *helper = NULL;
1227 ModestMailOperationPrivate *priv = NULL;
1228 ModestTnyFolderRules parent_rules, rules;
1230 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1231 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1232 g_return_if_fail (TNY_IS_FOLDER (folder));
1234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1236 /* Pick references for async calls */
1237 g_object_ref (folder);
1238 g_object_ref (parent);
1240 /* Get folder rules */
1241 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1242 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1244 /* The moveable restriction is applied also to copy operation */
1245 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
1246 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1247 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1248 _("mail_in_ui_folder_move_target_error"));
1250 /* Notify the queue */
1251 modest_mail_operation_notify_end (self);
1252 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1253 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1254 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1255 _("FIXME: parent folder does not accept new folders"));
1257 /* Notify the queue */
1258 modest_mail_operation_notify_end (self);
1260 helper = g_slice_new0 (XFerFolderAsyncHelper);
1261 helper->mail_op = self;
1263 /* Move/Copy folder */
1264 tny_folder_copy_async (folder,
1266 tny_folder_get_name (folder),
1269 transfer_folder_status_cb,
1275 /* ******************************************************************* */
1276 /* ************************** MSG ACTIONS ************************* */
1277 /* ******************************************************************* */
1279 void modest_mail_operation_get_msg (ModestMailOperation *self,
1281 GetMsgAsyncUserCallback user_callback,
1284 GetMsgAsyncHelper *helper = NULL;
1286 ModestMailOperationPrivate *priv;
1288 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1289 g_return_if_fail (TNY_IS_HEADER (header));
1291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1292 folder = tny_header_get_folder (header);
1294 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1296 /* Get message from folder */
1298 helper = g_slice_new0 (GetMsgAsyncHelper);
1299 helper->mail_op = self;
1300 helper->user_callback = user_callback;
1301 helper->pending_ops = 1;
1302 helper->user_data = user_data;
1304 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1306 g_object_unref (G_OBJECT (folder));
1308 /* Set status failed and set an error */
1309 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1310 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1311 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1312 _("Error trying to get a message. No folder found for header"));
1317 get_msg_cb (TnyFolder *folder,
1323 GetMsgAsyncHelper *helper = NULL;
1324 ModestMailOperation *self = NULL;
1325 ModestMailOperationPrivate *priv = NULL;
1327 helper = (GetMsgAsyncHelper *) user_data;
1328 g_return_if_fail (helper != NULL);
1329 self = helper->mail_op;
1330 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1333 helper->pending_ops--;
1335 /* Check errors and cancel */
1337 priv->error = g_error_copy (*error);
1338 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1342 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1343 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1344 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1345 _("Error trying to refresh the contents of %s"),
1346 tny_folder_get_name (folder));
1350 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1352 /* If user defined callback function was defined, call it */
1353 if (helper->user_callback) {
1354 helper->user_callback (self, NULL, msg, helper->user_data);
1359 if (helper->pending_ops == 0) {
1360 g_slice_free (GetMsgAsyncHelper, helper);
1362 /* Notify about operation end */
1363 modest_mail_operation_notify_end (self);
1368 get_msg_status_cb (GObject *obj,
1372 GetMsgAsyncHelper *helper = NULL;
1373 ModestMailOperation *self;
1374 ModestMailOperationPrivate *priv;
1375 ModestMailOperationState *state;
1377 g_return_if_fail (status != NULL);
1378 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1380 helper = (GetMsgAsyncHelper *) user_data;
1381 g_return_if_fail (helper != NULL);
1383 self = helper->mail_op;
1384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1386 if ((status->position == 1) && (status->of_total == 100))
1392 state = modest_mail_operation_clone_state (self);
1393 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1394 g_slice_free (ModestMailOperationState, state);
1397 /****************************************************/
1399 ModestMailOperation *mail_op;
1401 GetMsgAsyncUserCallback user_callback;
1403 GDestroyNotify notify;
1407 GetMsgAsyncUserCallback user_callback;
1411 ModestMailOperation *mail_op;
1412 } NotifyGetMsgsInfo;
1416 * Used by get_msgs_full_thread to call the user_callback for each
1417 * message that has been read
1420 notify_get_msgs_full (gpointer data)
1422 NotifyGetMsgsInfo *info;
1424 info = (NotifyGetMsgsInfo *) data;
1426 /* Call the user callback */
1427 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1429 g_slice_free (NotifyGetMsgsInfo, info);
1435 * Used by get_msgs_full_thread to free al the thread resources and to
1436 * call the destroy function for the passed user_data
1439 get_msgs_full_destroyer (gpointer data)
1441 GetFullMsgsInfo *info;
1443 info = (GetFullMsgsInfo *) data;
1446 info->notify (info->user_data);
1449 g_object_unref (info->headers);
1450 g_slice_free (GetFullMsgsInfo, info);
1456 get_msgs_full_thread (gpointer thr_user_data)
1458 GetFullMsgsInfo *info;
1459 ModestMailOperationPrivate *priv = NULL;
1460 TnyIterator *iter = NULL;
1462 info = (GetFullMsgsInfo *) thr_user_data;
1463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1465 iter = tny_list_create_iterator (info->headers);
1466 while (!tny_iterator_is_done (iter)) {
1470 header = TNY_HEADER (tny_iterator_get_current (iter));
1471 folder = tny_header_get_folder (header);
1473 /* Get message from folder */
1476 /* The callback will call it per each header */
1477 msg = tny_folder_get_msg (folder, header, &(priv->error));
1480 ModestMailOperationState *state;
1485 /* notify progress */
1486 state = modest_mail_operation_clone_state (info->mail_op);
1487 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1488 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1489 pair, (GDestroyNotify) modest_pair_free);
1491 /* The callback is the responsible for
1492 freeing the message */
1493 if (info->user_callback) {
1494 NotifyGetMsgsInfo *info_notify;
1495 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1496 info_notify->user_callback = info->user_callback;
1497 info_notify->mail_op = info->mail_op;
1498 info_notify->header = g_object_ref (header);
1499 info_notify->msg = g_object_ref (msg);
1500 info_notify->user_data = info->user_data;
1501 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1502 notify_get_msgs_full,
1505 g_object_unref (msg);
1508 /* Set status failed and set an error */
1509 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1510 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1511 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1512 "Error trying to get a message. No folder found for header");
1514 g_object_unref (header);
1515 tny_iterator_next (iter);
1518 /* Notify about operation end */
1519 g_idle_add (notify_update_account_queue, info->mail_op);
1521 /* Free thread resources. Will be called after all previous idles */
1522 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1528 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1529 TnyList *header_list,
1530 GetMsgAsyncUserCallback user_callback,
1532 GDestroyNotify notify)
1535 ModestMailOperationPrivate *priv = NULL;
1536 GetFullMsgsInfo *info = NULL;
1537 gboolean size_ok = TRUE;
1539 GError *error = NULL;
1541 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1543 /* Init mail operation */
1544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1545 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1547 priv->total = tny_list_get_length(header_list);
1549 /* Get msg size limit */
1550 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1551 MODEST_CONF_MSG_SIZE_LIMIT,
1554 g_clear_error (&error);
1555 max_size = G_MAXINT;
1557 max_size = max_size * KB;
1560 /* Check message size limits. If there is only one message
1561 always retrieve it */
1562 if (tny_list_get_length (header_list) > 1) {
1565 iter = tny_list_create_iterator (header_list);
1566 while (!tny_iterator_is_done (iter) && size_ok) {
1567 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1568 if (tny_header_get_message_size (header) >= max_size)
1570 g_object_unref (header);
1571 tny_iterator_next (iter);
1573 g_object_unref (iter);
1577 /* Create the info */
1578 info = g_slice_new0 (GetFullMsgsInfo);
1579 info->mail_op = self;
1580 info->user_callback = user_callback;
1581 info->user_data = user_data;
1582 info->headers = g_object_ref (header_list);
1583 info->notify = notify;
1585 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1587 /* FIXME: the error msg is different for pop */
1588 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1589 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1590 _("emev_ni_ui_imap_msg_sizelimit_error"));
1591 /* Remove from queue and free resources */
1592 modest_mail_operation_notify_end (self);
1600 modest_mail_operation_remove_msg (ModestMailOperation *self,
1602 gboolean remove_to_trash)
1605 ModestMailOperationPrivate *priv;
1607 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1608 g_return_if_fail (TNY_IS_HEADER (header));
1610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1611 folder = tny_header_get_folder (header);
1613 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1615 /* Delete or move to trash */
1616 if (remove_to_trash) {
1617 TnyFolder *trash_folder;
1618 TnyStoreAccount *store_account;
1620 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1621 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1622 TNY_FOLDER_TYPE_TRASH);
1627 headers = tny_simple_list_new ();
1628 tny_list_append (headers, G_OBJECT (header));
1629 g_object_unref (header);
1632 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1633 g_object_unref (headers);
1634 /* g_object_unref (trash_folder); */
1636 ModestMailOperationPrivate *priv;
1638 /* Set status failed and set an error */
1639 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1641 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1642 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1643 _("Error trying to delete a message. Trash folder not found"));
1646 g_object_unref (G_OBJECT (store_account));
1648 tny_folder_remove_msg (folder, header, &(priv->error));
1650 tny_folder_sync(folder, TRUE, &(priv->error));
1655 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1657 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1660 g_object_unref (G_OBJECT (folder));
1662 /* Notify about operation end */
1663 modest_mail_operation_notify_end (self);
1667 transfer_msgs_status_cb (GObject *obj,
1671 XFerMsgAsyncHelper *helper = NULL;
1672 ModestMailOperation *self;
1673 ModestMailOperationPrivate *priv;
1674 ModestMailOperationState *state;
1677 g_return_if_fail (status != NULL);
1678 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1680 helper = (XFerMsgAsyncHelper *) user_data;
1681 g_return_if_fail (helper != NULL);
1683 self = helper->mail_op;
1684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1686 if ((status->position == 1) && (status->of_total == 100))
1689 priv->done = status->position;
1690 priv->total = status->of_total;
1692 state = modest_mail_operation_clone_state (self);
1693 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1694 g_slice_free (ModestMailOperationState, state);
1699 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1701 XFerMsgAsyncHelper *helper;
1702 ModestMailOperation *self;
1703 ModestMailOperationPrivate *priv;
1705 helper = (XFerMsgAsyncHelper *) user_data;
1706 self = helper->mail_op;
1708 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1711 priv->error = g_error_copy (*err);
1713 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1714 } else if (cancelled) {
1715 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1716 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1717 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1718 _("Error trying to refresh the contents of %s"),
1719 tny_folder_get_name (folder));
1722 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1725 /* If user defined callback function was defined, call it */
1726 if (helper->user_callback) {
1727 helper->user_callback (priv->source, helper->user_data);
1731 g_object_unref (helper->headers);
1732 g_object_unref (helper->dest_folder);
1733 g_object_unref (helper->mail_op);
1734 g_slice_free (XFerMsgAsyncHelper, helper);
1735 g_object_unref (folder);
1737 /* Notify about operation end */
1738 modest_mail_operation_notify_end (self);
1742 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1745 gboolean delete_original,
1746 XferMsgsAsynUserCallback user_callback,
1749 ModestMailOperationPrivate *priv;
1751 TnyFolder *src_folder;
1752 XFerMsgAsyncHelper *helper;
1754 ModestTnyFolderRules rules;
1756 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1757 g_return_if_fail (TNY_IS_LIST (headers));
1758 g_return_if_fail (TNY_IS_FOLDER (folder));
1760 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1763 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1765 /* Apply folder rules */
1766 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1768 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1769 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1770 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1771 _("FIXME: folder does not accept msgs"));
1772 /* Notify the queue */
1773 modest_mail_operation_notify_end (self);
1777 /* Create the helper */
1778 helper = g_slice_new0 (XFerMsgAsyncHelper);
1779 helper->mail_op = g_object_ref(self);
1780 helper->dest_folder = g_object_ref(folder);
1781 helper->headers = g_object_ref(headers);
1782 helper->user_callback = user_callback;
1783 helper->user_data = user_data;
1785 /* Get source folder */
1786 iter = tny_list_create_iterator (headers);
1787 header = TNY_HEADER (tny_iterator_get_current (iter));
1788 src_folder = tny_header_get_folder (header);
1789 g_object_unref (header);
1790 g_object_unref (iter);
1792 /* Transfer messages */
1793 tny_folder_transfer_msgs_async (src_folder,
1798 transfer_msgs_status_cb,
1804 on_refresh_folder (TnyFolder *folder,
1809 ModestMailOperation *self;
1810 ModestMailOperationPrivate *priv;
1812 self = MODEST_MAIL_OPERATION (user_data);
1813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1816 priv->error = g_error_copy (*error);
1817 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1823 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1824 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1825 _("Error trying to refresh the contents of %s"),
1826 tny_folder_get_name (folder));
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1834 g_object_unref (folder);
1836 /* Notify about operation end */
1837 modest_mail_operation_notify_end (self);
1841 on_refresh_folder_status_update (GObject *obj,
1845 ModestMailOperation *self;
1846 ModestMailOperationPrivate *priv;
1847 ModestMailOperationState *state;
1849 g_return_if_fail (status != NULL);
1850 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1852 self = MODEST_MAIL_OPERATION (user_data);
1853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1855 priv->done = status->position;
1856 priv->total = status->of_total;
1858 state = modest_mail_operation_clone_state (self);
1859 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1860 g_slice_free (ModestMailOperationState, state);
1864 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1867 ModestMailOperationPrivate *priv;
1869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1871 /* Pick a reference */
1872 g_object_ref (folder);
1874 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1876 /* Refresh the folder. TODO: tinymail could issue a status
1877 updates before the callback call then this could happen. We
1878 must review the design */
1879 tny_folder_refresh_async (folder,
1881 on_refresh_folder_status_update,
1887 * It's used by the mail operation queue to notify the observers
1888 * attached to that signal that the operation finished. We need to use
1889 * that because tinymail does not give us the progress of a given
1890 * operation when it finishes (it directly calls the operation
1894 modest_mail_operation_notify_end (ModestMailOperation *self)
1896 ModestMailOperationState *state;
1898 /* Notify the observers about the mail opertation end */
1899 state = modest_mail_operation_clone_state (self);
1900 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1901 g_slice_free (ModestMailOperationState, state);
1903 /* Notify the queue */
1904 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);