1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
34 #include <tny-mime-part.h>
35 #include <tny-store-account.h>
36 #include <tny-folder-store.h>
37 #include <tny-folder-store-query.h>
38 #include <tny-camel-stream.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <tny-folder-observer.h>
43 #include <camel/camel-stream-mem.h>
44 #include <glib/gi18n.h>
45 #include "modest-platform.h"
46 #include <modest-tny-account.h>
47 #include <modest-tny-send-queue.h>
48 #include <modest-runtime.h>
49 #include "modest-text-utils.h"
50 #include "modest-tny-msg.h"
51 #include "modest-tny-folder.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-marshal.h"
54 #include "modest-error.h"
58 /* 'private'/'protected' functions */
59 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
60 static void modest_mail_operation_init (ModestMailOperation *obj);
61 static void modest_mail_operation_finalize (GObject *obj);
63 static void get_msg_cb (TnyFolder *folder,
69 static void get_msg_status_cb (GObject *obj,
73 static void modest_mail_operation_notify_end (ModestMailOperation *self);
75 enum _ModestMailOperationSignals
77 PROGRESS_CHANGED_SIGNAL,
82 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
83 struct _ModestMailOperationPrivate {
89 ErrorCheckingUserCallback error_checking;
90 ModestMailOperationStatus status;
91 ModestMailOperationTypeOperation op_type;
94 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95 MODEST_TYPE_MAIL_OPERATION, \
96 ModestMailOperationPrivate))
98 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
99 priv->status = new_status;\
102 typedef struct _GetMsgAsyncHelper {
103 ModestMailOperation *mail_op;
104 GetMsgAsyncUserCallback user_callback;
109 typedef struct _XFerMsgAsyncHelper
111 ModestMailOperation *mail_op;
113 TnyFolder *dest_folder;
114 XferMsgsAsynUserCallback user_callback;
116 } XFerMsgAsyncHelper;
119 static GObjectClass *parent_class = NULL;
121 static guint signals[NUM_SIGNALS] = {0};
124 modest_mail_operation_get_type (void)
126 static GType my_type = 0;
128 static const GTypeInfo my_info = {
129 sizeof(ModestMailOperationClass),
130 NULL, /* base init */
131 NULL, /* base finalize */
132 (GClassInitFunc) modest_mail_operation_class_init,
133 NULL, /* class finalize */
134 NULL, /* class data */
135 sizeof(ModestMailOperation),
137 (GInstanceInitFunc) modest_mail_operation_init,
140 my_type = g_type_register_static (G_TYPE_OBJECT,
141 "ModestMailOperation",
148 modest_mail_operation_class_init (ModestMailOperationClass *klass)
150 GObjectClass *gobject_class;
151 gobject_class = (GObjectClass*) klass;
153 parent_class = g_type_class_peek_parent (klass);
154 gobject_class->finalize = modest_mail_operation_finalize;
156 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
159 * ModestMailOperation::progress-changed
160 * @self: the #MailOperation that emits the signal
161 * @user_data: user data set when the signal handler was connected
163 * Emitted when the progress of a mail operation changes
165 signals[PROGRESS_CHANGED_SIGNAL] =
166 g_signal_new ("progress-changed",
167 G_TYPE_FROM_CLASS (gobject_class),
169 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
171 g_cclosure_marshal_VOID__POINTER,
172 G_TYPE_NONE, 1, G_TYPE_POINTER);
176 modest_mail_operation_init (ModestMailOperation *obj)
178 ModestMailOperationPrivate *priv;
180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
182 priv->account = NULL;
183 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
184 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
186 priv->error_checking = NULL;
193 modest_mail_operation_finalize (GObject *obj)
195 ModestMailOperationPrivate *priv;
197 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
200 g_error_free (priv->error);
204 g_object_unref (priv->source);
208 g_object_unref (priv->account);
209 priv->account = NULL;
213 G_OBJECT_CLASS(parent_class)->finalize (obj);
217 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
220 ModestMailOperation *obj;
221 ModestMailOperationPrivate *priv;
223 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
224 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
226 priv->op_type = op_type;
228 priv->source = g_object_ref(source);
234 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
236 ErrorCheckingUserCallback error_handler)
238 ModestMailOperation *obj;
239 ModestMailOperationPrivate *priv;
241 obj = modest_mail_operation_new (op_type, source);
242 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
244 g_return_val_if_fail (error_handler != NULL, obj);
245 priv->error_checking = error_handler;
251 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
253 ModestMailOperationPrivate *priv;
255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
256 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
258 if (priv->error_checking == NULL)
260 priv->error_checking (priv->source, self);
264 ModestMailOperationTypeOperation
265 modest_mail_operation_get_type_operation (ModestMailOperation *self)
267 ModestMailOperationPrivate *priv;
269 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
271 return priv->op_type;
275 modest_mail_operation_is_mine (ModestMailOperation *self,
278 ModestMailOperationPrivate *priv;
280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
281 if (priv->source == NULL) return FALSE;
283 return priv->source == me;
287 modest_mail_operation_get_source (ModestMailOperation *self)
289 ModestMailOperationPrivate *priv;
291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
293 return g_object_ref (priv->source);
296 ModestMailOperationStatus
297 modest_mail_operation_get_status (ModestMailOperation *self)
299 ModestMailOperationPrivate *priv;
301 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
302 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
303 MODEST_MAIL_OPERATION_STATUS_INVALID);
305 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
310 modest_mail_operation_get_error (ModestMailOperation *self)
312 ModestMailOperationPrivate *priv;
314 g_return_val_if_fail (self, NULL);
315 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
322 modest_mail_operation_cancel (ModestMailOperation *self)
324 ModestMailOperationPrivate *priv;
326 if (!MODEST_IS_MAIL_OPERATION (self)) {
327 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
333 /* TODO: Tinymail does not support cancel operation */
334 /* tny_account_cancel (); */
337 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
339 /* Notify about operation end */
340 modest_mail_operation_notify_end (self);
346 modest_mail_operation_get_task_done (ModestMailOperation *self)
348 ModestMailOperationPrivate *priv;
350 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
352 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
357 modest_mail_operation_get_task_total (ModestMailOperation *self)
359 ModestMailOperationPrivate *priv;
361 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
368 modest_mail_operation_is_finished (ModestMailOperation *self)
370 ModestMailOperationPrivate *priv;
371 gboolean retval = FALSE;
373 if (!MODEST_IS_MAIL_OPERATION (self)) {
374 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
378 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
380 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
381 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
382 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
383 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
393 modest_mail_operation_get_id (ModestMailOperation *self)
395 ModestMailOperationPrivate *priv;
397 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
399 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
404 modest_mail_operation_set_id (ModestMailOperation *self,
407 ModestMailOperationPrivate *priv;
409 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
416 * Creates an image of the current state of a mail operation, the
417 * caller must free it
419 static ModestMailOperationState *
420 modest_mail_operation_clone_state (ModestMailOperation *self)
422 ModestMailOperationState *state;
423 ModestMailOperationPrivate *priv;
425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
427 state = g_slice_new (ModestMailOperationState);
429 state->status = priv->status;
430 state->op_type = priv->op_type;
431 state->done = priv->done;
432 state->total = priv->total;
433 state->finished = modest_mail_operation_is_finished (self);
438 /* ******************************************************************* */
439 /* ************************** SEND ACTIONS ************************* */
440 /* ******************************************************************* */
443 modest_mail_operation_send_mail (ModestMailOperation *self,
444 TnyTransportAccount *transport_account,
447 TnySendQueue *send_queue = NULL;
448 ModestMailOperationPrivate *priv;
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 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
456 /* Get account and set it into mail_operation */
457 priv->account = g_object_ref (transport_account);
459 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
460 if (!TNY_IS_SEND_QUEUE(send_queue))
461 g_printerr ("modest: could not find send queue for account\n");
464 tny_send_queue_add (send_queue, msg, &err);
466 g_printerr ("modest: error adding msg to send queue: %s\n",
470 /* g_message ("modest: message added to send queue"); */
474 /* Notify about operation end */
475 modest_mail_operation_notify_end (self);
479 modest_mail_operation_send_new_mail (ModestMailOperation *self,
480 TnyTransportAccount *transport_account,
481 const gchar *from, const gchar *to,
482 const gchar *cc, const gchar *bcc,
483 const gchar *subject, const gchar *plain_body,
484 const gchar *html_body,
485 const GList *attachments_list,
486 TnyHeaderFlags priority_flags)
488 TnyMsg *new_msg = NULL;
489 ModestMailOperationPrivate *priv = NULL;
491 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
492 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
494 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
496 /* Get account and set it into mail_operation */
497 priv->account = g_object_ref (transport_account);
499 /* Check parametters */
501 /* Set status failed and set an error */
502 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
503 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
504 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
505 _("Error trying to send a mail. You need to set at least one recipient"));
509 if (html_body == NULL) {
510 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
512 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
515 g_printerr ("modest: failed to create a new msg\n");
519 /* TODO: add priority handling. It's received in the priority_flags operator, and
520 it should have effect in the sending operation */
522 /* Call mail operation */
523 modest_mail_operation_send_mail (self, transport_account, new_msg);
526 g_object_unref (G_OBJECT (new_msg));
530 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
531 TnyTransportAccount *transport_account,
532 const gchar *from, const gchar *to,
533 const gchar *cc, const gchar *bcc,
534 const gchar *subject, const gchar *plain_body,
535 const gchar *html_body,
536 const GList *attachments_list,
537 TnyHeaderFlags priority_flags)
540 TnyFolder *folder = NULL;
541 ModestMailOperationPrivate *priv = NULL;
544 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
545 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
549 /* Get account and set it into mail_operation */
550 priv->account = g_object_ref (transport_account);
552 if (html_body == NULL) {
553 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
555 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
558 g_printerr ("modest: failed to create a new msg\n");
562 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
564 g_printerr ("modest: failed to find Drafts folder\n");
568 tny_folder_add_msg (folder, msg, &err);
570 g_printerr ("modest: error adding msg to Drafts folder: %s",
576 modest_mail_operation_notify_end (self);
581 g_object_unref (G_OBJECT(msg));
583 g_object_unref (G_OBJECT(folder));
588 ModestMailOperation *mail_op;
589 TnyStoreAccount *account;
590 TnyTransportAccount *transport_account;
593 gchar *retrieve_type;
596 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
597 /* We use this folder observer to track the headers that have been
598 * added to a folder */
601 TnyList *new_headers;
602 } InternalFolderObserver;
606 } InternalFolderObserverClass;
608 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
610 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
611 internal_folder_observer,
613 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
617 foreach_add_item (gpointer header, gpointer user_data)
619 tny_list_prepend (TNY_LIST (user_data),
620 g_object_ref (G_OBJECT (header)));
623 /* This is the method that looks for new messages in a folder */
625 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
627 TnyFolderChangeChanged changed;
629 changed = tny_folder_change_get_changed (change);
631 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
634 /* Get added headers */
635 list = tny_simple_list_new ();
636 tny_folder_change_get_added_headers (change, list);
638 /* Add them to the folder observer */
639 tny_list_foreach (list, foreach_add_item,
640 ((InternalFolderObserver *)self)->new_headers);
642 g_object_unref (G_OBJECT (list));
647 internal_folder_observer_init (InternalFolderObserver *self)
649 self->new_headers = tny_simple_list_new ();
652 internal_folder_observer_finalize (GObject *object)
654 InternalFolderObserver *self;
656 self = (InternalFolderObserver *) object;
657 g_object_unref (self->new_headers);
659 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
662 tny_folder_observer_init (TnyFolderObserverIface *iface)
664 iface->update_func = internal_folder_observer_update;
667 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
669 GObjectClass *object_class;
671 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
672 object_class = (GObjectClass*) klass;
673 object_class->finalize = internal_folder_observer_finalize;
679 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
682 TnyList *folders = tny_simple_list_new ();
684 tny_folder_store_get_folders (store, folders, query, NULL);
685 iter = tny_list_create_iterator (folders);
687 while (!tny_iterator_is_done (iter)) {
689 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
691 tny_list_prepend (all_folders, G_OBJECT (folder));
692 recurse_folders (folder, query, all_folders);
693 g_object_unref (G_OBJECT (folder));
695 tny_iterator_next (iter);
697 g_object_unref (G_OBJECT (iter));
698 g_object_unref (G_OBJECT (folders));
702 * Issues the "progress-changed" signal. The timer won't be removed,
703 * so you must call g_source_remove to stop the signal emission
706 idle_notify_progress (gpointer data)
708 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
709 ModestMailOperationState *state;
711 state = modest_mail_operation_clone_state (mail_op);
712 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
713 g_slice_free (ModestMailOperationState, state);
719 * Issues the "progress-changed" signal and removes the timer. It uses
720 * a lock to ensure that the progress information of the mail
721 * operation is not modified while there are notifications pending
724 idle_notify_progress_once (gpointer data)
728 pair = (ModestPair *) data;
730 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
732 /* Free the state and the reference to the mail operation */
733 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
734 g_object_unref (pair->first);
740 * Used by update_account_thread to notify the queue from the main
741 * loop. We call it inside an idle call to achieve that
744 notify_update_account_queue (gpointer data)
746 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
748 modest_mail_operation_notify_end (mail_op);
749 g_object_unref (mail_op);
755 compare_headers_by_date (gconstpointer a,
758 TnyHeader **header1, **header2;
761 header1 = (TnyHeader **) a;
762 header2 = (TnyHeader **) b;
764 sent1 = tny_header_get_date_sent (*header1);
765 sent2 = tny_header_get_date_sent (*header2);
767 /* We want the most recent ones (greater time_t) at the
776 update_account_thread (gpointer thr_user_data)
778 UpdateAccountInfo *info;
779 TnyList *all_folders = NULL;
780 GPtrArray *new_headers;
781 TnyIterator *iter = NULL;
782 TnyFolderStoreQuery *query = NULL;
783 ModestMailOperationPrivate *priv;
785 info = (UpdateAccountInfo *) thr_user_data;
786 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
788 /* Get account and set it into mail_operation */
789 priv->account = g_object_ref (info->account);
791 /* Get all the folders We can do it synchronously because
792 we're already running in a different thread than the UI */
793 all_folders = tny_simple_list_new ();
794 query = tny_folder_store_query_new ();
795 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
796 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
801 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
805 iter = tny_list_create_iterator (all_folders);
806 while (!tny_iterator_is_done (iter)) {
807 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
809 recurse_folders (folder, query, all_folders);
810 tny_iterator_next (iter);
812 g_object_unref (G_OBJECT (iter));
814 /* Update status and notify. We need to call the notification
815 with a source functopm in order to call it from the main
816 loop. We need that in order not to get into trouble with
817 Gtk+. We use a timeout in order to provide more status
818 information, because the sync tinymail call does not
819 provide it for the moment */
820 gint timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
822 /* Refresh folders */
823 new_headers = g_ptr_array_new ();
824 iter = tny_list_create_iterator (all_folders);
825 while (!tny_iterator_is_done (iter) && !priv->error) {
827 InternalFolderObserver *observer;
828 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
830 /* Refresh the folder */
831 observer = g_object_new (internal_folder_observer_get_type (), NULL);
832 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
833 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
835 /* If the retrieve type is headers only do nothing more */
836 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
837 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
840 iter = tny_list_create_iterator (observer->new_headers);
841 while (!tny_iterator_is_done (iter)) {
842 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
843 /* Apply per-message size limits */
844 if (tny_header_get_message_size (header) < info->max_size)
845 g_ptr_array_add (new_headers, g_object_ref (header));
847 g_object_unref (header);
848 tny_iterator_next (iter);
850 g_object_unref (iter);
852 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
853 g_object_unref (observer);
856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
858 g_object_unref (G_OBJECT (folder));
859 tny_iterator_next (iter);
861 g_object_unref (G_OBJECT (iter));
862 g_source_remove (timeout);
864 if (new_headers->len > 0) {
868 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
870 /* Apply message count limit */
871 /* TODO if the number of messages exceeds the maximum, ask the
872 user to download them all */
874 priv->total = MIN (new_headers->len, info->retrieve_limit);
875 while ((msg_num < priv->total)) {
877 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
878 TnyFolder *folder = tny_header_get_folder (header);
879 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
880 ModestMailOperationState *state;
884 /* We can not just use the mail operation because the
885 values of done and total could change before the
887 state = modest_mail_operation_clone_state (info->mail_op);
888 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
889 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
890 pair, (GDestroyNotify) modest_pair_free);
892 g_object_unref (msg);
893 g_object_unref (folder);
897 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
898 g_ptr_array_free (new_headers, FALSE);
902 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
905 if (priv->account != NULL)
906 g_object_unref (priv->account);
907 priv->account = g_object_ref (info->transport_account);
909 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue
910 (info->transport_account);
912 timeout = g_timeout_add (250, idle_notify_progress, info->mail_op);
913 modest_tny_send_queue_try_to_send (send_queue);
914 g_source_remove (timeout);
916 g_object_unref (G_OBJECT(send_queue));
918 /* Check if the operation was a success */
920 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
922 /* Update the last updated key */
923 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
924 tny_account_get_id (TNY_ACCOUNT (info->account)),
925 MODEST_ACCOUNT_LAST_UPDATED,
931 /* Notify about operation end. Note that the info could be
932 freed before this idle happens, but the mail operation will
934 g_idle_add (notify_update_account_queue, info->mail_op);
937 g_object_unref (query);
938 g_object_unref (all_folders);
939 g_object_unref (info->account);
940 g_object_unref (info->transport_account);
941 g_free (info->retrieve_type);
942 g_slice_free (UpdateAccountInfo, info);
948 modest_mail_operation_update_account (ModestMailOperation *self,
949 const gchar *account_name)
952 UpdateAccountInfo *info;
953 ModestMailOperationPrivate *priv;
954 ModestAccountMgr *mgr;
955 TnyStoreAccount *modest_account;
956 TnyTransportAccount *transport_account;
958 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
959 g_return_val_if_fail (account_name, FALSE);
961 /* Init mail operation. Set total and done to 0, and do not
962 update them, this way the progress objects will know that
963 we have no clue about the number of the objects */
964 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
967 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
969 /* Get the Modest account */
970 modest_account = (TnyStoreAccount *)
971 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
973 TNY_ACCOUNT_TYPE_STORE);
975 if (!modest_account) {
976 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
977 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
978 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
979 "cannot get tny store account for %s\n", account_name);
980 modest_mail_operation_notify_end (self);
984 /* Get the transport account, we can not do it in the thread
985 due to some problems with dbus */
986 transport_account = (TnyTransportAccount *)
987 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
989 if (!transport_account) {
990 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
991 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
992 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
993 "cannot get tny transport account for %s\n", account_name);
994 modest_mail_operation_notify_end (self);
998 /* Create the helper object */
999 info = g_slice_new (UpdateAccountInfo);
1000 info->mail_op = self;
1001 info->account = modest_account;
1002 info->transport_account = transport_account;
1004 /* Get the message size limit */
1005 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1006 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1007 if (info->max_size == 0)
1008 info->max_size = G_MAXINT;
1010 info->max_size = info->max_size * KB;
1012 /* Get per-account retrieval type */
1013 mgr = modest_runtime_get_account_mgr ();
1014 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1015 MODEST_ACCOUNT_RETRIEVE, FALSE);
1017 /* Get per-account message amount retrieval limit */
1018 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1019 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1020 if (info->retrieve_limit == 0)
1021 info->retrieve_limit = G_MAXINT;
1023 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1028 /* ******************************************************************* */
1029 /* ************************** STORE ACTIONS ************************* */
1030 /* ******************************************************************* */
1034 modest_mail_operation_create_folder (ModestMailOperation *self,
1035 TnyFolderStore *parent,
1038 ModestTnyFolderRules rules;
1039 ModestMailOperationPrivate *priv;
1040 TnyFolder *new_folder = NULL;
1041 gboolean can_create = FALSE;
1043 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1044 g_return_val_if_fail (name, NULL);
1046 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1048 /* Get account and set it into mail_operation */
1049 priv->account = tny_folder_get_account (TNY_FOLDER(parent));
1052 if (!TNY_IS_FOLDER (parent)) {
1053 /* Set status failed and set an error */
1054 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1055 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1056 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1057 _("mail_in_ui_folder_create_error"));
1059 /* Check folder rules */
1060 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1061 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1062 /* Set status failed and set an error */
1063 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1064 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1065 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1066 _("mail_in_ui_folder_create_error"));
1073 /* Create the folder */
1074 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1075 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1078 /* Notify about operation end */
1079 modest_mail_operation_notify_end (self);
1085 modest_mail_operation_remove_folder (ModestMailOperation *self,
1087 gboolean remove_to_trash)
1089 TnyAccount *account;
1090 ModestMailOperationPrivate *priv;
1091 ModestTnyFolderRules rules;
1093 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1094 g_return_if_fail (TNY_IS_FOLDER (folder));
1096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1098 /* Check folder rules */
1099 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1100 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1101 /* Set status failed and set an error */
1102 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1103 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1104 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1105 _("mail_in_ui_folder_delete_error"));
1109 /* Get the account */
1110 account = tny_folder_get_account (folder);
1111 priv->account = g_object_ref(account);
1113 /* Delete folder or move to trash */
1114 if (remove_to_trash) {
1115 TnyFolder *trash_folder = NULL;
1116 trash_folder = modest_tny_account_get_special_folder (account,
1117 TNY_FOLDER_TYPE_TRASH);
1118 /* TODO: error_handling */
1119 modest_mail_operation_xfer_folder (self, folder,
1120 TNY_FOLDER_STORE (trash_folder), TRUE);
1122 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1124 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1125 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1128 g_object_unref (G_OBJECT (parent));
1130 g_object_unref (G_OBJECT (account));
1133 /* Notify about operation end */
1134 modest_mail_operation_notify_end (self);
1138 transfer_folder_status_cb (GObject *obj,
1142 ModestMailOperation *self;
1143 ModestMailOperationPrivate *priv;
1144 ModestMailOperationState *state;
1146 g_return_if_fail (status != NULL);
1147 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1149 self = MODEST_MAIL_OPERATION (user_data);
1150 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1152 if ((status->position == 1) && (status->of_total == 100))
1155 priv->done = status->position;
1156 priv->total = status->of_total;
1158 state = modest_mail_operation_clone_state (self);
1159 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1160 g_slice_free (ModestMailOperationState, state);
1165 transfer_folder_cb (TnyFolder *folder,
1166 TnyFolderStore *into,
1168 TnyFolder *new_folder, GError **err,
1171 ModestMailOperation *self = NULL;
1172 ModestMailOperationPrivate *priv = NULL;
1174 self = MODEST_MAIL_OPERATION (user_data);
1176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1179 priv->error = g_error_copy (*err);
1181 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1182 } else if (cancelled) {
1183 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1184 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1185 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1186 _("Transference of %s was cancelled."),
1187 tny_folder_get_name (folder));
1190 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1194 g_object_unref (folder);
1195 g_object_unref (into);
1196 if (new_folder != NULL)
1197 g_object_unref (new_folder);
1199 /* Notify about operation end */
1200 modest_mail_operation_notify_end (self);
1204 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1206 TnyFolderStore *parent,
1207 gboolean delete_original)
1209 ModestMailOperationPrivate *priv = NULL;
1210 ModestTnyFolderRules parent_rules, rules;
1212 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1213 g_return_if_fail (TNY_IS_FOLDER (folder));
1214 g_return_if_fail (TNY_IS_FOLDER (parent));
1216 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1218 /* Get account and set it into mail_operation */
1219 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1220 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1222 /* Get folder rules */
1223 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1224 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1226 if (!TNY_IS_FOLDER_STORE (parent)) {
1230 /* The moveable restriction is applied also to copy operation */
1231 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1232 /* Set status failed and set an error */
1233 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1234 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1235 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1236 _("mail_in_ui_folder_move_target_error"));
1238 /* Notify the queue */
1239 modest_mail_operation_notify_end (self);
1240 } else if (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1241 /* Set status failed and set an error */
1242 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1243 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1244 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1245 _("FIXME: parent folder does not accept new folders"));
1247 /* Notify the queue */
1248 modest_mail_operation_notify_end (self);
1250 /* Pick references for async calls */
1251 g_object_ref (folder);
1252 g_object_ref (parent);
1254 /* Move/Copy folder */
1255 tny_folder_copy_async (folder,
1257 tny_folder_get_name (folder),
1260 transfer_folder_status_cb,
1266 modest_mail_operation_rename_folder (ModestMailOperation *self,
1270 ModestMailOperationPrivate *priv;
1271 ModestTnyFolderRules rules;
1273 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1274 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1275 g_return_if_fail (name);
1277 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1279 /* Get account and set it into mail_operation */
1280 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1282 /* Check folder rules */
1283 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1284 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1285 /* Set status failed and set an error */
1286 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1287 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1288 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1289 _("FIXME: unable to rename"));
1291 /* Notify about operation end */
1292 modest_mail_operation_notify_end (self);
1294 /* Rename. Camel handles folder subscription/unsubscription */
1295 TnyFolderStore *into;
1297 into = tny_folder_get_folder_store (folder);
1298 tny_folder_copy_async (folder, into, name, TRUE,
1300 transfer_folder_status_cb,
1303 g_object_unref (into);
1308 /* ******************************************************************* */
1309 /* ************************** MSG ACTIONS ************************* */
1310 /* ******************************************************************* */
1312 void modest_mail_operation_get_msg (ModestMailOperation *self,
1314 GetMsgAsyncUserCallback user_callback,
1317 GetMsgAsyncHelper *helper = NULL;
1319 ModestMailOperationPrivate *priv;
1321 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1322 g_return_if_fail (TNY_IS_HEADER (header));
1324 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1325 folder = tny_header_get_folder (header);
1327 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1329 /* Get message from folder */
1331 /* Get account and set it into mail_operation */
1332 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1334 helper = g_slice_new0 (GetMsgAsyncHelper);
1335 helper->mail_op = self;
1336 helper->user_callback = user_callback;
1337 helper->pending_ops = 1;
1338 helper->user_data = user_data;
1340 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1342 g_object_unref (G_OBJECT (folder));
1344 /* Set status failed and set an error */
1345 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1346 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1347 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1348 _("Error trying to get a message. No folder found for header"));
1350 /* Notify the queue */
1351 modest_mail_operation_notify_end (self);
1356 get_msg_cb (TnyFolder *folder,
1362 GetMsgAsyncHelper *helper = NULL;
1363 ModestMailOperation *self = NULL;
1364 ModestMailOperationPrivate *priv = NULL;
1366 helper = (GetMsgAsyncHelper *) user_data;
1367 g_return_if_fail (helper != NULL);
1368 self = helper->mail_op;
1369 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1370 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1372 helper->pending_ops--;
1374 /* Check errors and cancel */
1376 priv->error = g_error_copy (*error);
1377 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1381 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1382 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1383 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1384 _("Error trying to refresh the contents of %s"),
1385 tny_folder_get_name (folder));
1389 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1391 /* If user defined callback function was defined, call it */
1392 if (helper->user_callback) {
1393 helper->user_callback (self, NULL, msg, helper->user_data);
1398 if (helper->pending_ops == 0) {
1399 g_slice_free (GetMsgAsyncHelper, helper);
1401 /* Notify about operation end */
1402 modest_mail_operation_notify_end (self);
1407 get_msg_status_cb (GObject *obj,
1411 GetMsgAsyncHelper *helper = NULL;
1412 ModestMailOperation *self;
1413 ModestMailOperationPrivate *priv;
1414 ModestMailOperationState *state;
1416 g_return_if_fail (status != NULL);
1417 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1419 helper = (GetMsgAsyncHelper *) user_data;
1420 g_return_if_fail (helper != NULL);
1422 self = helper->mail_op;
1423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1425 if ((status->position == 1) && (status->of_total == 100))
1431 state = modest_mail_operation_clone_state (self);
1432 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1433 g_slice_free (ModestMailOperationState, state);
1436 /****************************************************/
1438 ModestMailOperation *mail_op;
1440 GetMsgAsyncUserCallback user_callback;
1442 GDestroyNotify notify;
1446 GetMsgAsyncUserCallback user_callback;
1450 ModestMailOperation *mail_op;
1451 } NotifyGetMsgsInfo;
1455 * Used by get_msgs_full_thread to call the user_callback for each
1456 * message that has been read
1459 notify_get_msgs_full (gpointer data)
1461 NotifyGetMsgsInfo *info;
1463 info = (NotifyGetMsgsInfo *) data;
1465 /* Call the user callback */
1466 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
1468 g_slice_free (NotifyGetMsgsInfo, info);
1474 * Used by get_msgs_full_thread to free al the thread resources and to
1475 * call the destroy function for the passed user_data
1478 get_msgs_full_destroyer (gpointer data)
1480 GetFullMsgsInfo *info;
1482 info = (GetFullMsgsInfo *) data;
1485 info->notify (info->user_data);
1488 g_object_unref (info->headers);
1489 g_slice_free (GetFullMsgsInfo, info);
1495 get_msgs_full_thread (gpointer thr_user_data)
1497 GetFullMsgsInfo *info;
1498 ModestMailOperationPrivate *priv = NULL;
1499 TnyIterator *iter = NULL;
1501 info = (GetFullMsgsInfo *) thr_user_data;
1502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1504 iter = tny_list_create_iterator (info->headers);
1505 while (!tny_iterator_is_done (iter)) {
1509 header = TNY_HEADER (tny_iterator_get_current (iter));
1510 folder = tny_header_get_folder (header);
1512 /* Get message from folder */
1515 /* The callback will call it per each header */
1516 msg = tny_folder_get_msg (folder, header, &(priv->error));
1519 ModestMailOperationState *state;
1524 /* notify progress */
1525 state = modest_mail_operation_clone_state (info->mail_op);
1526 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1527 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1528 pair, (GDestroyNotify) modest_pair_free);
1530 /* The callback is the responsible for
1531 freeing the message */
1532 if (info->user_callback) {
1533 NotifyGetMsgsInfo *info_notify;
1534 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1535 info_notify->user_callback = info->user_callback;
1536 info_notify->mail_op = info->mail_op;
1537 info_notify->header = g_object_ref (header);
1538 info_notify->msg = g_object_ref (msg);
1539 info_notify->user_data = info->user_data;
1540 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1541 notify_get_msgs_full,
1544 g_object_unref (msg);
1547 /* Set status failed and set an error */
1548 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1549 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1550 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1551 "Error trying to get a message. No folder found for header");
1553 g_object_unref (header);
1554 tny_iterator_next (iter);
1557 /* Notify about operation end */
1558 g_idle_add (notify_update_account_queue, info->mail_op);
1560 /* Free thread resources. Will be called after all previous idles */
1561 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1567 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1568 TnyList *header_list,
1569 GetMsgAsyncUserCallback user_callback,
1571 GDestroyNotify notify)
1573 TnyHeader *header = NULL;
1574 TnyFolder *folder = NULL;
1576 ModestMailOperationPrivate *priv = NULL;
1577 GetFullMsgsInfo *info = NULL;
1578 gboolean size_ok = TRUE;
1580 GError *error = NULL;
1581 TnyIterator *iter = NULL;
1583 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1585 /* Init mail operation */
1586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1587 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1589 priv->total = tny_list_get_length(header_list);
1591 /* Get account and set it into mail_operation */
1592 if (tny_list_get_length (header_list) > 1) {
1593 iter = tny_list_create_iterator (header_list);
1594 header = TNY_HEADER (tny_iterator_get_current (iter));
1595 folder = tny_header_get_folder (header);
1596 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1597 g_object_unref (header);
1598 g_object_unref (folder);
1601 /* Get msg size limit */
1602 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1603 MODEST_CONF_MSG_SIZE_LIMIT,
1606 g_clear_error (&error);
1607 max_size = G_MAXINT;
1609 max_size = max_size * KB;
1612 /* Check message size limits. If there is only one message
1613 always retrieve it */
1615 while (!tny_iterator_is_done (iter) && size_ok) {
1616 header = TNY_HEADER (tny_iterator_get_current (iter));
1617 if (tny_header_get_message_size (header) >= max_size)
1619 g_object_unref (header);
1620 tny_iterator_next (iter);
1622 g_object_unref (iter);
1626 /* Create the info */
1627 info = g_slice_new0 (GetFullMsgsInfo);
1628 info->mail_op = self;
1629 info->user_callback = user_callback;
1630 info->user_data = user_data;
1631 info->headers = g_object_ref (header_list);
1632 info->notify = notify;
1634 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1636 /* Set status failed and set an error */
1637 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1638 /* FIXME: the error msg is different for pop */
1639 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1640 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1641 _("emev_ni_ui_imap_msg_sizelimit_error"));
1642 /* Remove from queue and free resources */
1643 modest_mail_operation_notify_end (self);
1651 modest_mail_operation_remove_msg (ModestMailOperation *self,
1653 gboolean remove_to_trash)
1656 ModestMailOperationPrivate *priv;
1658 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1659 g_return_if_fail (TNY_IS_HEADER (header));
1661 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1662 folder = tny_header_get_folder (header);
1664 /* Get account and set it into mail_operation */
1665 priv->account = tny_folder_get_account (TNY_FOLDER(folder));
1667 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1669 /* Delete or move to trash */
1670 if (remove_to_trash) {
1671 TnyFolder *trash_folder;
1672 TnyStoreAccount *store_account;
1674 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1675 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1676 TNY_FOLDER_TYPE_TRASH);
1681 headers = tny_simple_list_new ();
1682 tny_list_append (headers, G_OBJECT (header));
1683 g_object_unref (header);
1686 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1687 g_object_unref (headers);
1688 /* g_object_unref (trash_folder); */
1690 ModestMailOperationPrivate *priv;
1692 /* Set status failed and set an error */
1693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1694 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1695 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1696 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1697 _("Error trying to delete a message. Trash folder not found"));
1700 g_object_unref (G_OBJECT (store_account));
1702 tny_folder_remove_msg (folder, header, &(priv->error));
1704 tny_folder_sync(folder, TRUE, &(priv->error));
1709 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1711 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1714 g_object_unref (G_OBJECT (folder));
1716 /* Notify about operation end */
1717 modest_mail_operation_notify_end (self);
1721 transfer_msgs_status_cb (GObject *obj,
1725 XFerMsgAsyncHelper *helper = NULL;
1726 ModestMailOperation *self;
1727 ModestMailOperationPrivate *priv;
1728 ModestMailOperationState *state;
1731 g_return_if_fail (status != NULL);
1732 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1734 helper = (XFerMsgAsyncHelper *) user_data;
1735 g_return_if_fail (helper != NULL);
1737 self = helper->mail_op;
1738 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1740 if ((status->position == 1) && (status->of_total == 100))
1743 priv->done = status->position;
1744 priv->total = status->of_total;
1746 state = modest_mail_operation_clone_state (self);
1747 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1748 g_slice_free (ModestMailOperationState, state);
1753 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1755 XFerMsgAsyncHelper *helper;
1756 ModestMailOperation *self;
1757 ModestMailOperationPrivate *priv;
1759 helper = (XFerMsgAsyncHelper *) user_data;
1760 self = helper->mail_op;
1762 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1765 priv->error = g_error_copy (*err);
1767 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1768 } else if (cancelled) {
1769 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1770 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1771 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1772 _("Error trying to refresh the contents of %s"),
1773 tny_folder_get_name (folder));
1776 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1779 /* If user defined callback function was defined, call it */
1780 if (helper->user_callback) {
1781 helper->user_callback (priv->source, helper->user_data);
1785 g_object_unref (helper->headers);
1786 g_object_unref (helper->dest_folder);
1787 g_object_unref (helper->mail_op);
1788 g_slice_free (XFerMsgAsyncHelper, helper);
1789 g_object_unref (folder);
1791 /* Notify about operation end */
1792 modest_mail_operation_notify_end (self);
1796 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1799 gboolean delete_original,
1800 XferMsgsAsynUserCallback user_callback,
1803 ModestMailOperationPrivate *priv;
1805 TnyFolder *src_folder;
1806 XFerMsgAsyncHelper *helper;
1808 ModestTnyFolderRules rules;
1810 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1811 g_return_if_fail (TNY_IS_LIST (headers));
1812 g_return_if_fail (TNY_IS_FOLDER (folder));
1814 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1817 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1819 /* Apply folder rules */
1820 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1822 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1823 /* Set status failed and set an error */
1824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1825 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1826 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1827 _("FIXME: folder does not accept msgs"));
1828 /* Notify the queue */
1829 modest_mail_operation_notify_end (self);
1833 /* Create the helper */
1834 helper = g_slice_new0 (XFerMsgAsyncHelper);
1835 helper->mail_op = g_object_ref(self);
1836 helper->dest_folder = g_object_ref(folder);
1837 helper->headers = g_object_ref(headers);
1838 helper->user_callback = user_callback;
1839 helper->user_data = user_data;
1841 /* Get source folder */
1842 iter = tny_list_create_iterator (headers);
1843 header = TNY_HEADER (tny_iterator_get_current (iter));
1844 src_folder = tny_header_get_folder (header);
1845 g_object_unref (header);
1846 g_object_unref (iter);
1848 /* Get account and set it into mail_operation */
1849 priv->account = tny_folder_get_account (src_folder);
1851 /* Transfer messages */
1852 tny_folder_transfer_msgs_async (src_folder,
1857 transfer_msgs_status_cb,
1863 on_refresh_folder (TnyFolder *folder,
1868 ModestMailOperation *self;
1869 ModestMailOperationPrivate *priv;
1871 self = MODEST_MAIL_OPERATION (user_data);
1872 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1875 priv->error = g_error_copy (*error);
1876 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1881 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1882 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1883 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1884 _("Error trying to refresh the contents of %s"),
1885 tny_folder_get_name (folder));
1889 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1893 g_object_unref (folder);
1895 /* Notify about operation end */
1896 modest_mail_operation_notify_end (self);
1900 on_refresh_folder_status_update (GObject *obj,
1904 ModestMailOperation *self;
1905 ModestMailOperationPrivate *priv;
1906 ModestMailOperationState *state;
1908 g_return_if_fail (status != NULL);
1909 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1911 self = MODEST_MAIL_OPERATION (user_data);
1912 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1914 priv->done = status->position;
1915 priv->total = status->of_total;
1917 state = modest_mail_operation_clone_state (self);
1918 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1919 g_slice_free (ModestMailOperationState, state);
1923 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1926 ModestMailOperationPrivate *priv;
1928 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1930 /* Pick a reference */
1931 g_object_ref (folder);
1933 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1935 /* Get account and set it into mail_operation */
1936 priv->account = tny_folder_get_account (folder);
1938 /* Refresh the folder. TODO: tinymail could issue a status
1939 updates before the callback call then this could happen. We
1940 must review the design */
1941 tny_folder_refresh_async (folder,
1943 on_refresh_folder_status_update,
1949 * It's used by the mail operation queue to notify the observers
1950 * attached to that signal that the operation finished. We need to use
1951 * that because tinymail does not give us the progress of a given
1952 * operation when it finishes (it directly calls the operation
1956 modest_mail_operation_notify_end (ModestMailOperation *self)
1958 ModestMailOperationState *state;
1960 /* Notify the observers about the mail opertation end */
1961 state = modest_mail_operation_clone_state (self);
1962 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1963 g_slice_free (ModestMailOperationState, state);
1965 /* Notify the queue */
1966 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);