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.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers, guint num_elements);
100 static int compare_headers_by_date (gconstpointer a,
103 static void sync_folder_finish_callback (TnyFolder *self,
108 static gboolean _check_memory_low (ModestMailOperation *mail_op);
110 /* Helpers for the update account operation (send & receive)*/
113 ModestMailOperation *mail_op;
115 UpdateAccountCallback callback;
120 TnyFolderObserver *inbox_observer;
121 RetrieveAllCallback retrieve_all_cb;
122 gboolean interactive;
126 static void destroy_update_account_info (UpdateAccountInfo *info);
128 static void update_account_send_mail (UpdateAccountInfo *info);
130 static void update_account_get_msg_async_cb (TnyFolder *folder,
136 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
137 TnyList *new_headers);
139 enum _ModestMailOperationSignals
141 PROGRESS_CHANGED_SIGNAL,
142 OPERATION_STARTED_SIGNAL,
143 OPERATION_FINISHED_SIGNAL,
147 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
148 struct _ModestMailOperationPrivate {
154 ErrorCheckingUserCallback error_checking;
155 gpointer error_checking_user_data;
156 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
157 ModestMailOperationStatus status;
158 ModestMailOperationTypeOperation op_type;
161 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
162 MODEST_TYPE_MAIL_OPERATION, \
163 ModestMailOperationPrivate))
165 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
166 priv->status = new_status;\
171 GetMsgAsyncUserCallback user_callback;
173 TnyIterator *more_msgs;
175 ModestMailOperation *mail_op;
176 GDestroyNotify destroy_notify;
177 gint last_total_bytes;
178 gint sum_total_bytes;
182 typedef struct _RefreshAsyncHelper {
183 ModestMailOperation *mail_op;
184 RefreshAsyncUserCallback user_callback;
186 } RefreshAsyncHelper;
188 typedef struct _XFerMsgsAsyncHelper
190 ModestMailOperation *mail_op;
192 TnyIterator *more_msgs;
193 TnyFolder *dest_folder;
194 XferMsgsAsyncUserCallback user_callback;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 } XFerMsgsAsyncHelper;
202 typedef struct _XFerFolderAsyncHelper
204 ModestMailOperation *mail_op;
205 XferFolderAsyncUserCallback user_callback;
207 } XFerFolderAsyncHelper;
209 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
213 static void modest_mail_operation_create_msg (ModestMailOperation *self,
214 const gchar *from, const gchar *to,
215 const gchar *cc, const gchar *bcc,
216 const gchar *subject, const gchar *plain_body,
217 const gchar *html_body, const GList *attachments_list,
218 const GList *images_list,
219 TnyHeaderFlags priority_flags,
220 ModestMailOperationCreateMsgCallback callback,
223 static gboolean idle_notify_queue (gpointer data);
226 ModestMailOperation *mail_op;
234 GList *attachments_list;
236 TnyHeaderFlags priority_flags;
237 ModestMailOperationCreateMsgCallback callback;
243 ModestMailOperation *mail_op;
245 ModestMailOperationCreateMsgCallback callback;
250 static GObjectClass *parent_class = NULL;
252 static guint signals[NUM_SIGNALS] = {0};
255 modest_mail_operation_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMailOperationClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_mail_operation_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMailOperation),
268 (GInstanceInitFunc) modest_mail_operation_init,
271 my_type = g_type_register_static (G_TYPE_OBJECT,
272 "ModestMailOperation",
279 modest_mail_operation_class_init (ModestMailOperationClass *klass)
281 GObjectClass *gobject_class;
282 gobject_class = (GObjectClass*) klass;
284 parent_class = g_type_class_peek_parent (klass);
285 gobject_class->finalize = modest_mail_operation_finalize;
287 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
290 * ModestMailOperation::progress-changed
291 * @self: the #MailOperation that emits the signal
292 * @user_data: user data set when the signal handler was connected
294 * Emitted when the progress of a mail operation changes
296 signals[PROGRESS_CHANGED_SIGNAL] =
297 g_signal_new ("progress-changed",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
302 g_cclosure_marshal_VOID__POINTER,
303 G_TYPE_NONE, 1, G_TYPE_POINTER);
307 * This signal is issued whenever a mail operation starts, and
308 * starts mean when the tinymail operation is issued. This
309 * means that it could happen that something wrong happens and
310 * the tinymail function is never called. In this situation a
311 * operation-finished will be issued without any
314 signals[OPERATION_STARTED_SIGNAL] =
315 g_signal_new ("operation-started",
316 G_TYPE_FROM_CLASS (gobject_class),
318 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
320 g_cclosure_marshal_VOID__VOID,
325 * This signal is issued whenever a mail operation
326 * finishes. Note that this signal could be issued without any
327 * previous "operation-started" signal, because this last one
328 * is only issued when the tinymail operation is successfully
331 signals[OPERATION_FINISHED_SIGNAL] =
332 g_signal_new ("operation-finished",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
337 g_cclosure_marshal_VOID__VOID,
342 modest_mail_operation_init (ModestMailOperation *obj)
344 ModestMailOperationPrivate *priv;
346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
348 priv->account = NULL;
349 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
355 priv->error_checking = NULL;
356 priv->error_checking_user_data = NULL;
360 modest_mail_operation_finalize (GObject *obj)
362 ModestMailOperationPrivate *priv;
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
369 g_error_free (priv->error);
373 g_object_unref (priv->source);
377 g_object_unref (priv->account);
378 priv->account = NULL;
382 G_OBJECT_CLASS(parent_class)->finalize (obj);
386 modest_mail_operation_new (GObject *source)
388 ModestMailOperation *obj;
389 ModestMailOperationPrivate *priv;
391 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
395 priv->source = g_object_ref(source);
401 modest_mail_operation_new_with_error_handling (GObject *source,
402 ErrorCheckingUserCallback error_handler,
404 ErrorCheckingUserDataDestroyer error_handler_destroyer)
406 ModestMailOperation *obj;
407 ModestMailOperationPrivate *priv;
409 obj = modest_mail_operation_new (source);
410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 g_return_val_if_fail (error_handler != NULL, obj);
413 priv->error_checking = error_handler;
414 priv->error_checking_user_data = user_data;
415 priv->error_checking_user_data_destroyer = error_handler_destroyer;
421 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
423 ModestMailOperationPrivate *priv;
425 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
428 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
430 /* Call the user callback */
431 if (priv->error_checking != NULL)
432 priv->error_checking (self, priv->error_checking_user_data);
436 ModestMailOperationTypeOperation
437 modest_mail_operation_get_type_operation (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
442 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
446 return priv->op_type;
450 modest_mail_operation_is_mine (ModestMailOperation *self,
453 ModestMailOperationPrivate *priv;
455 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 if (priv->source == NULL) return FALSE;
461 return priv->source == me;
465 modest_mail_operation_get_source (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
474 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
478 return (priv->source) ? g_object_ref (priv->source) : NULL;
481 ModestMailOperationStatus
482 modest_mail_operation_get_status (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
487 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
488 MODEST_MAIL_OPERATION_STATUS_INVALID);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
492 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
493 return MODEST_MAIL_OPERATION_STATUS_INVALID;
500 modest_mail_operation_get_error (ModestMailOperation *self)
502 ModestMailOperationPrivate *priv;
504 g_return_val_if_fail (self, NULL);
505 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
510 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
518 modest_mail_operation_cancel (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
521 gboolean canceled = FALSE;
523 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
528 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
530 /* Cancel the mail operation */
531 g_return_val_if_fail (priv->account, FALSE);
532 tny_account_cancel (priv->account);
534 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
535 ModestTnySendQueue *queue;
536 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
539 /* Cancel the sending of the following next messages */
540 if (TNY_IS_SEND_QUEUE (queue))
541 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
548 modest_mail_operation_get_task_done (ModestMailOperation *self)
550 ModestMailOperationPrivate *priv;
552 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
560 modest_mail_operation_get_task_total (ModestMailOperation *self)
562 ModestMailOperationPrivate *priv;
564 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
572 modest_mail_operation_is_finished (ModestMailOperation *self)
574 ModestMailOperationPrivate *priv;
575 gboolean retval = FALSE;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
582 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
583 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
584 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
585 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
595 * Creates an image of the current state of a mail operation, the
596 * caller must free it
598 static ModestMailOperationState *
599 modest_mail_operation_clone_state (ModestMailOperation *self)
601 ModestMailOperationState *state;
602 ModestMailOperationPrivate *priv;
604 g_return_val_if_fail (self, NULL);
605 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
606 g_return_val_if_fail (priv, NULL);
611 state = g_slice_new (ModestMailOperationState);
613 state->status = priv->status;
614 state->op_type = priv->op_type;
615 state->done = priv->done;
616 state->total = priv->total;
617 state->finished = modest_mail_operation_is_finished (self);
618 state->bytes_done = 0;
619 state->bytes_total = 0;
624 /* ******************************************************************* */
625 /* ************************** SEND ACTIONS ************************* */
626 /* ******************************************************************* */
630 ModestMailOperation *mail_op;
635 send_mail_common_cb (gboolean cancelled,
637 SendNewMailHelper *helper)
639 ModestMailOperationPrivate *priv;
640 ModestMailOperation *self;
642 self = helper->mail_op;
643 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
645 if (cancelled || err)
649 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
650 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
651 "Error adding a msg to the send queue\n");
652 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
654 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
659 modest_mail_operation_notify_end (self);
661 g_object_unref (helper->mail_op);
662 g_slice_free (SendNewMailHelper, helper);
666 send_mail_on_sync_async_cb (TnyFolder *self,
671 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
675 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
681 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
685 idle_create_msg_cb (gpointer idle_data)
687 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
689 /* This is a GDK lock because we are an idle callback and
690 * info->callback can contain Gtk+ code */
692 gdk_threads_enter (); /* CHECKED */
693 info->callback (info->mail_op, info->msg, info->userdata);
695 g_object_unref (info->mail_op);
697 g_object_unref (info->msg);
698 g_slice_free (CreateMsgIdleInfo, info);
699 gdk_threads_leave (); /* CHECKED */
705 create_msg_thread (gpointer thread_data)
707 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
708 TnyMsg *new_msg = NULL;
709 ModestMailOperationPrivate *priv;
712 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
713 if (info->html_body == NULL) {
714 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
715 info->bcc, info->subject, info->plain_body,
716 info->attachments_list, &attached,
719 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
720 info->bcc, info->subject, info->html_body,
721 info->plain_body, info->attachments_list,
722 info->images_list, &attached,
729 /* Set priority flags in message */
730 header = tny_msg_get_header (new_msg);
731 tny_header_set_flag (header, info->priority_flags);
733 /* Set attachment flags in message */
734 if (info->attachments_list != NULL && attached > 0)
735 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
737 g_object_unref (G_OBJECT(header));
739 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
741 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
742 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
743 "modest: failed to create a new msg\n");
751 g_free (info->plain_body);
752 g_free (info->html_body);
753 g_free (info->subject);
754 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
755 g_list_free (info->attachments_list);
756 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
757 g_list_free (info->images_list);
759 if (info->callback) {
760 CreateMsgIdleInfo *idle_info;
761 idle_info = g_slice_new0 (CreateMsgIdleInfo);
762 idle_info->mail_op = g_object_ref (info->mail_op);
763 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
764 idle_info->callback = info->callback;
765 idle_info->userdata = info->userdata;
766 g_idle_add (idle_create_msg_cb, idle_info);
768 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
771 g_object_unref (info->mail_op);
772 g_slice_free (CreateMsgInfo, info);
773 if (new_msg) g_object_unref(new_msg);
779 modest_mail_operation_create_msg (ModestMailOperation *self,
780 const gchar *from, const gchar *to,
781 const gchar *cc, const gchar *bcc,
782 const gchar *subject, const gchar *plain_body,
783 const gchar *html_body,
784 const GList *attachments_list,
785 const GList *images_list,
786 TnyHeaderFlags priority_flags,
787 ModestMailOperationCreateMsgCallback callback,
790 CreateMsgInfo *info = NULL;
792 info = g_slice_new0 (CreateMsgInfo);
793 info->mail_op = g_object_ref (self);
795 info->from = g_strdup (from);
796 info->to = g_strdup (to);
797 info->cc = g_strdup (cc);
798 info->bcc = g_strdup (bcc);
799 info->subject = g_strdup (subject);
800 info->plain_body = g_strdup (plain_body);
801 info->html_body = g_strdup (html_body);
802 info->attachments_list = g_list_copy ((GList *) attachments_list);
803 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
804 info->images_list = g_list_copy ((GList *) images_list);
805 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
806 info->priority_flags = priority_flags;
808 info->callback = callback;
809 info->userdata = userdata;
811 g_thread_create (create_msg_thread, info, FALSE, NULL);
816 TnyTransportAccount *transport_account;
821 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
825 TnySendQueue *send_queue = NULL;
826 ModestMailOperationPrivate *priv = NULL;
827 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
828 TnyFolder *draft_folder = NULL;
829 TnyFolder *outbox_folder = NULL;
830 TnyHeader *header = NULL;
832 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
835 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
836 modest_mail_operation_notify_end (self);
840 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
841 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
842 modest_mail_operation_notify_end (self);
846 /* Add message to send queue */
847 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
848 if (!TNY_IS_SEND_QUEUE(send_queue)) {
850 g_error_free (priv->error);
853 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
854 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
855 "modest: could not find send queue for account\n");
856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
857 modest_mail_operation_notify_end (self);
860 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
861 helper->mail_op = g_object_ref (self);
862 helper->notify = (info->draft_msg == NULL);
864 /* Add the msg to the queue. The callback will free
866 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
868 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
872 if (info->draft_msg != NULL) {
873 TnyList *tmp_headers = NULL;
874 TnyFolder *folder = NULL;
875 TnyFolder *src_folder = NULL;
876 TnyFolderType folder_type;
877 TnyTransportAccount *transport_account = NULL;
878 SendNewMailHelper *helper = NULL;
880 /* To remove the old mail from its source folder, we need to get the
881 * transport account of the original draft message (the transport account
882 * might have been changed by the user) */
883 header = tny_msg_get_header (info->draft_msg);
884 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
885 modest_runtime_get_account_store(), header);
886 if (transport_account == NULL)
887 transport_account = g_object_ref(info->transport_account);
888 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
889 TNY_FOLDER_TYPE_DRAFTS);
890 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
891 TNY_FOLDER_TYPE_OUTBOX);
892 g_object_unref(transport_account);
895 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
897 modest_mail_operation_notify_end (self);
900 if (!outbox_folder) {
901 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
903 modest_mail_operation_notify_end (self);
907 folder = tny_msg_get_folder (info->draft_msg);
908 if (folder == NULL) {
909 modest_mail_operation_notify_end (self);
912 folder_type = modest_tny_folder_guess_folder_type (folder);
914 if (folder_type == TNY_FOLDER_TYPE_INVALID)
915 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
917 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
918 src_folder = outbox_folder;
920 src_folder = draft_folder;
922 /* Note: This can fail (with a warning) if the message is not really already in a folder,
923 * because this function requires it to have a UID. */
924 helper = g_slice_new (SendNewMailHelper);
925 helper->mail_op = g_object_ref (self);
926 helper->notify = TRUE;
928 tmp_headers = tny_simple_list_new ();
929 tny_list_append (tmp_headers, (GObject*) header);
930 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
931 g_object_unref (tmp_headers);
932 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
934 g_object_unref (folder);
939 g_object_unref (header);
941 g_object_unref (info->draft_msg);
943 g_object_unref (draft_folder);
945 g_object_unref (outbox_folder);
946 if (info->transport_account)
947 g_object_unref (info->transport_account);
948 g_slice_free (SendNewMailInfo, info);
952 modest_mail_operation_send_new_mail (ModestMailOperation *self,
953 TnyTransportAccount *transport_account,
955 const gchar *from, const gchar *to,
956 const gchar *cc, const gchar *bcc,
957 const gchar *subject, const gchar *plain_body,
958 const gchar *html_body,
959 const GList *attachments_list,
960 const GList *images_list,
961 TnyHeaderFlags priority_flags)
963 ModestMailOperationPrivate *priv = NULL;
964 SendNewMailInfo *info;
966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
967 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
969 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
970 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
971 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
972 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
974 modest_mail_operation_notify_start (self);
976 /* Check parametters */
978 /* Set status failed and set an error */
979 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
980 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
981 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
982 _("Error trying to send a mail. You need to set at least one recipient"));
983 modest_mail_operation_notify_end (self);
986 info = g_slice_new0 (SendNewMailInfo);
987 info->transport_account = transport_account;
988 if (transport_account)
989 g_object_ref (transport_account);
990 info->draft_msg = draft_msg;
992 g_object_ref (draft_msg);
995 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
996 attachments_list, images_list, priority_flags,
997 modest_mail_operation_send_new_mail_cb, info);
1003 TnyTransportAccount *transport_account;
1005 SaveToDraftstCallback callback;
1009 ModestMailOperation *mailop;
1010 } SaveToDraftsAddMsgInfo;
1013 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1018 ModestMailOperationPrivate *priv = NULL;
1019 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1020 GError *io_error = NULL;
1022 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1024 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1025 io_error = priv->error;
1029 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1030 g_error_free(priv->error);
1033 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1035 if ((!priv->error) && (info->draft_msg != NULL)) {
1036 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1037 TnyFolder *src_folder = tny_header_get_folder (header);
1039 /* Remove the old draft */
1040 tny_folder_remove_msg (src_folder, header, NULL);
1042 /* Synchronize to expunge and to update the msg counts */
1043 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1044 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1046 g_object_unref (G_OBJECT(header));
1047 g_object_unref (G_OBJECT(src_folder));
1051 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1053 g_error_free (io_error);
1056 } else if (io_error) {
1057 priv->error = io_error;
1058 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1060 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1063 /* Call the user callback */
1065 info->callback (info->mailop, info->msg, info->user_data);
1067 if (info->transport_account)
1068 g_object_unref (G_OBJECT(info->transport_account));
1069 if (info->draft_msg)
1070 g_object_unref (G_OBJECT (info->draft_msg));
1072 g_object_unref (G_OBJECT(info->drafts));
1074 g_object_unref (G_OBJECT (info->msg));
1076 modest_mail_operation_notify_end (info->mailop);
1077 g_object_unref(info->mailop);
1078 g_slice_free (SaveToDraftsAddMsgInfo, info);
1083 TnyTransportAccount *transport_account;
1085 SaveToDraftstCallback callback;
1090 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1094 TnyFolder *drafts = NULL;
1095 ModestMailOperationPrivate *priv = NULL;
1096 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1101 if (!(priv->error)) {
1102 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1103 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1104 "modest: failed to create a new msg\n");
1107 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1108 TNY_FOLDER_TYPE_DRAFTS);
1109 if (!drafts && !(priv->error)) {
1110 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1111 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1112 "modest: failed to create a new msg\n");
1116 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1117 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1118 cb_info->transport_account = g_object_ref(info->transport_account);
1119 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1120 cb_info->callback = info->callback;
1121 cb_info->user_data = info->user_data;
1122 cb_info->drafts = g_object_ref(drafts);
1123 cb_info->msg = g_object_ref(msg);
1124 cb_info->mailop = g_object_ref(self);
1125 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1128 /* Call the user callback */
1129 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1131 info->callback (self, msg, info->user_data);
1132 modest_mail_operation_notify_end (self);
1136 g_object_unref (G_OBJECT(drafts));
1137 if (info->draft_msg)
1138 g_object_unref (G_OBJECT (info->draft_msg));
1139 if (info->transport_account)
1140 g_object_unref (G_OBJECT(info->transport_account));
1141 g_slice_free (SaveToDraftsInfo, info);
1145 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1146 TnyTransportAccount *transport_account,
1148 const gchar *from, const gchar *to,
1149 const gchar *cc, const gchar *bcc,
1150 const gchar *subject, const gchar *plain_body,
1151 const gchar *html_body,
1152 const GList *attachments_list,
1153 const GList *images_list,
1154 TnyHeaderFlags priority_flags,
1155 SaveToDraftstCallback callback,
1158 ModestMailOperationPrivate *priv = NULL;
1159 SaveToDraftsInfo *info = NULL;
1161 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1162 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1164 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1166 /* Get account and set it into mail_operation */
1167 priv->account = g_object_ref (transport_account);
1168 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1170 info = g_slice_new0 (SaveToDraftsInfo);
1171 info->transport_account = g_object_ref (transport_account);
1172 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1173 info->callback = callback;
1174 info->user_data = user_data;
1176 modest_mail_operation_notify_start (self);
1177 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1178 attachments_list, images_list, priority_flags,
1179 modest_mail_operation_save_to_drafts_cb, info);
1184 ModestMailOperation *mail_op;
1185 TnyMimePart *mime_part;
1187 GetMimePartSizeCallback callback;
1189 } GetMimePartSizeInfo;
1191 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1192 /* We use this folder observer to track the headers that have been
1193 * added to a folder */
1196 TnyList *new_headers;
1197 } InternalFolderObserver;
1200 GObjectClass parent;
1201 } InternalFolderObserverClass;
1203 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1205 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1206 internal_folder_observer,
1208 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1212 foreach_add_item (gpointer header, gpointer user_data)
1214 tny_list_prepend (TNY_LIST (user_data),
1218 /* This is the method that looks for new messages in a folder */
1220 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1222 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1224 TnyFolderChangeChanged changed;
1226 changed = tny_folder_change_get_changed (change);
1228 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1231 /* Get added headers */
1232 list = tny_simple_list_new ();
1233 tny_folder_change_get_added_headers (change, list);
1235 /* Add them to the folder observer */
1236 tny_list_foreach (list, foreach_add_item,
1237 derived->new_headers);
1239 g_object_unref (G_OBJECT (list));
1244 internal_folder_observer_init (InternalFolderObserver *self)
1246 self->new_headers = tny_simple_list_new ();
1249 internal_folder_observer_finalize (GObject *object)
1251 InternalFolderObserver *self;
1253 self = (InternalFolderObserver *) object;
1254 g_object_unref (self->new_headers);
1256 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1259 tny_folder_observer_init (TnyFolderObserverIface *iface)
1261 iface->update = internal_folder_observer_update;
1264 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1266 GObjectClass *object_class;
1268 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1269 object_class = (GObjectClass*) klass;
1270 object_class->finalize = internal_folder_observer_finalize;
1274 destroy_update_account_info (UpdateAccountInfo *info)
1276 g_free (info->account_name);
1277 g_object_unref (info->folders);
1278 g_object_unref (info->mail_op);
1279 g_slice_free (UpdateAccountInfo, info);
1284 update_account_send_mail (UpdateAccountInfo *info)
1286 TnyTransportAccount *transport_account = NULL;
1287 ModestTnyAccountStore *account_store;
1289 account_store = modest_runtime_get_account_store ();
1291 /* We don't try to send messages while sending mails is blocked */
1292 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1295 /* Get the transport account */
1296 transport_account = (TnyTransportAccount *)
1297 modest_tny_account_store_get_transport_account_for_open_connection (account_store,
1298 info->account_name);
1300 if (transport_account) {
1301 ModestTnySendQueue *send_queue;
1305 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1306 g_object_unref (transport_account);
1308 if (TNY_IS_SEND_QUEUE (send_queue)) {
1309 /* Get outbox folder */
1310 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1311 if (outbox) { /* this could fail in some cases */
1312 num_messages = tny_folder_get_all_count (outbox);
1313 g_object_unref (outbox);
1315 g_warning ("%s: could not get outbox", __FUNCTION__);
1319 if (num_messages != 0) {
1320 /* Reenable suspended items */
1321 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1324 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1325 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1333 update_account_get_msg_async_cb (TnyFolder *folder,
1339 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1340 ModestMailOperationPrivate *priv;
1342 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1345 if (TNY_IS_MSG (msg)) {
1346 TnyHeader *header = tny_msg_get_header (msg);
1349 ModestMailOperationState *state;
1350 state = modest_mail_operation_clone_state (msg_info->mail_op);
1351 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1352 state->bytes_done = msg_info->sum_total_bytes;
1353 state->bytes_total = msg_info->total_bytes;
1355 /* Notify the status change. Only notify about changes
1356 referred to bytes */
1357 g_signal_emit (G_OBJECT (msg_info->mail_op),
1358 signals[PROGRESS_CHANGED_SIGNAL],
1361 g_object_unref (header);
1362 g_slice_free (ModestMailOperationState, state);
1366 if (priv->done == priv->total) {
1367 TnyList *new_headers;
1368 UpdateAccountInfo *info;
1370 /* After getting all the messages send the ones in the
1372 info = (UpdateAccountInfo *) msg_info->user_data;
1373 update_account_send_mail (info);
1375 /* Check if the operation was a success */
1377 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1379 /* Call the user callback and free */
1380 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1381 update_account_notify_user_and_free (info, new_headers);
1382 g_object_unref (new_headers);
1384 /* Delete the helper */
1385 g_object_unref (msg_info->more_msgs);
1386 g_object_unref (msg_info->mail_op);
1387 g_slice_free (GetMsgInfo, msg_info);
1392 update_account_notify_user_and_free (UpdateAccountInfo *info,
1393 TnyList *new_headers)
1395 /* Set the account back to not busy */
1396 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1397 info->account_name, FALSE);
1401 info->callback (info->mail_op, new_headers, info->user_data);
1403 /* Mail operation end */
1404 modest_mail_operation_notify_end (info->mail_op);
1408 g_object_unref (new_headers);
1409 destroy_update_account_info (info);
1413 inbox_refreshed_cb (TnyFolder *inbox,
1418 UpdateAccountInfo *info;
1419 ModestMailOperationPrivate *priv;
1420 TnyIterator *new_headers_iter;
1421 GPtrArray *new_headers_array = NULL;
1422 gint max_size, retrieve_limit, i;
1423 ModestAccountMgr *mgr;
1424 ModestAccountRetrieveType retrieve_type;
1425 TnyList *new_headers = NULL;
1426 gboolean headers_only, ignore_limit;
1428 info = (UpdateAccountInfo *) user_data;
1429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1430 mgr = modest_runtime_get_account_mgr ();
1432 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1433 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1435 if (canceled || err) {
1436 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1438 priv->error = g_error_copy (err);
1440 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1441 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1444 tny_folder_remove_observer (inbox, info->inbox_observer);
1445 g_object_unref (info->inbox_observer);
1446 info->inbox_observer = NULL;
1448 /* Notify the user about the error and then exit */
1449 update_account_notify_user_and_free (info, NULL);
1454 /* Try to send anyway */
1458 /* Get the message max size */
1459 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1460 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1462 max_size = G_MAXINT;
1464 max_size = max_size * KB;
1466 /* Create the new headers array. We need it to sort the
1467 new headers by date */
1468 new_headers_array = g_ptr_array_new ();
1469 if (info->inbox_observer) {
1470 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1471 while (!tny_iterator_is_done (new_headers_iter)) {
1472 TnyHeader *header = NULL;
1474 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1475 /* Apply per-message size limits */
1476 if (tny_header_get_message_size (header) < max_size)
1477 g_ptr_array_add (new_headers_array, g_object_ref (header));
1479 g_object_unref (header);
1480 tny_iterator_next (new_headers_iter);
1482 g_object_unref (new_headers_iter);
1484 tny_folder_remove_observer (inbox, info->inbox_observer);
1485 g_object_unref (info->inbox_observer);
1486 info->inbox_observer = NULL;
1489 if (new_headers_array->len == 0) {
1490 g_ptr_array_free (new_headers_array, FALSE);
1494 /* Get per-account message amount retrieval limit */
1495 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1496 if (retrieve_limit == 0)
1497 retrieve_limit = G_MAXINT;
1499 /* Get per-account retrieval type */
1500 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1501 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1504 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1506 /* Ask the users if they want to retrieve all the messages
1507 even though the limit was exceeded */
1508 ignore_limit = FALSE;
1509 if (new_headers_array->len > retrieve_limit) {
1510 /* Ask the user if a callback has been specified and
1511 if the mail operation has a source (this means that
1512 was invoked by the user and not automatically by a
1514 if (info->retrieve_all_cb && priv->source)
1515 ignore_limit = info->retrieve_all_cb (priv->source,
1516 new_headers_array->len,
1520 /* Copy the headers to a list and free the array */
1521 new_headers = tny_simple_list_new ();
1522 for (i=0; i < new_headers_array->len; i++) {
1523 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1524 tny_list_append (new_headers, G_OBJECT (header));
1526 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1527 g_ptr_array_free (new_headers_array, FALSE);
1529 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1532 GetMsgInfo *msg_info;
1536 priv->total = tny_list_get_length (new_headers);
1538 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1540 iter = tny_list_create_iterator (new_headers);
1542 /* Create the message info */
1543 msg_info = g_slice_new0 (GetMsgInfo);
1544 msg_info->mail_op = g_object_ref (info->mail_op);
1545 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1546 msg_info->more_msgs = g_object_ref (iter);
1547 msg_info->user_data = info;
1549 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1550 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1551 TnyFolder *folder = tny_header_get_folder (header);
1553 /* Get message in an async way */
1554 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1557 g_object_unref (folder);
1560 tny_iterator_next (iter);
1562 g_object_unref (iter);
1564 /* The mail operation will finish when the last
1565 message is retrieved */
1569 /* If we don't have to retrieve the new messages then
1571 update_account_send_mail (info);
1573 /* Check if the operation was a success */
1575 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1577 /* Call the user callback and free */
1578 update_account_notify_user_and_free (info, new_headers);
1582 inbox_refresh_status_update (GObject *obj,
1586 UpdateAccountInfo *info = NULL;
1587 ModestMailOperation *self = NULL;
1588 ModestMailOperationPrivate *priv = NULL;
1589 ModestMailOperationState *state;
1591 g_return_if_fail (user_data != NULL);
1592 g_return_if_fail (status != NULL);
1594 /* Show only the status information we want */
1595 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1598 info = (UpdateAccountInfo *) user_data;
1599 self = info->mail_op;
1600 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1602 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1604 priv->done = status->position;
1605 priv->total = status->of_total;
1607 state = modest_mail_operation_clone_state (self);
1609 /* This is not a GDK lock because we are a Tinymail callback and
1610 * Tinymail already acquires the Gdk lock */
1611 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1613 g_slice_free (ModestMailOperationState, state);
1617 recurse_folders_async_cb (TnyFolderStore *folder_store,
1623 UpdateAccountInfo *info;
1624 ModestMailOperationPrivate *priv;
1626 info = (UpdateAccountInfo *) user_data;
1627 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1629 if (err || canceled) {
1630 /* If the error was previosly set by another callback
1631 don't set it again */
1633 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1635 priv->error = g_error_copy (err);
1637 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1638 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1642 /* We're not getting INBOX children if we don't want to poke all */
1643 TnyIterator *iter = tny_list_create_iterator (list);
1644 while (!tny_iterator_is_done (iter)) {
1645 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1647 /* Add to the list of all folders */
1648 tny_list_append (info->folders, (GObject *) folder);
1650 if (info->poke_all) {
1651 TnyList *folders = tny_simple_list_new ();
1652 /* Add pending call */
1653 info->pending_calls++;
1655 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1656 recurse_folders_async_cb,
1658 g_object_unref (folders);
1661 g_object_unref (G_OBJECT (folder));
1663 tny_iterator_next (iter);
1665 g_object_unref (G_OBJECT (iter));
1668 /* Remove my own pending call */
1669 info->pending_calls--;
1671 /* This means that we have all the folders */
1672 if (info->pending_calls == 0) {
1673 TnyIterator *iter_all_folders;
1674 TnyFolder *inbox = NULL;
1676 /* If there was any error do not continue */
1678 update_account_notify_user_and_free (info, NULL);
1682 iter_all_folders = tny_list_create_iterator (info->folders);
1684 /* Do a poke status over all folders */
1685 while (!tny_iterator_is_done (iter_all_folders) &&
1686 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1687 TnyFolder *folder = NULL;
1689 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1691 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1692 /* Get a reference to the INBOX */
1693 inbox = g_object_ref (folder);
1695 /* Issue a poke status over the folder */
1697 tny_folder_poke_status (folder);
1700 /* Free and go to next */
1701 g_object_unref (folder);
1702 tny_iterator_next (iter_all_folders);
1704 g_object_unref (iter_all_folders);
1706 /* Refresh the INBOX */
1708 /* Refresh the folder. Our observer receives
1709 * the new emails during folder refreshes, so
1710 * we can use observer->new_headers
1712 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1713 tny_folder_add_observer (inbox, info->inbox_observer);
1715 /* Refresh the INBOX */
1716 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1717 g_object_unref (inbox);
1719 /* We could not perform the inbox refresh but
1720 we'll try to send mails anyway */
1721 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1727 modest_mail_operation_update_account (ModestMailOperation *self,
1728 const gchar *account_name,
1730 gboolean interactive,
1731 RetrieveAllCallback retrieve_all_cb,
1732 UpdateAccountCallback callback,
1735 UpdateAccountInfo *info = NULL;
1736 ModestMailOperationPrivate *priv = NULL;
1737 ModestTnyAccountStore *account_store = NULL;
1739 ModestMailOperationState *state;
1741 /* Init mail operation */
1742 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1745 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1746 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1748 /* Get the store account */
1749 account_store = modest_runtime_get_account_store ();
1751 modest_tny_account_store_get_server_account (account_store,
1753 TNY_ACCOUNT_TYPE_STORE);
1755 /* The above function could return NULL */
1756 if (!priv->account) {
1757 /* Check if the operation was a success */
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1761 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1763 /* Call the user callback */
1765 callback (self, NULL, user_data);
1767 /* Notify about operation end */
1768 modest_mail_operation_notify_end (self);
1773 /* We have once seen priv->account getting finalized during this code,
1774 * therefore adding a reference (bug #82296) */
1776 g_object_ref (priv->account);
1778 /* Create the helper object */
1779 info = g_slice_new0 (UpdateAccountInfo);
1780 info->pending_calls = 1;
1781 info->folders = tny_simple_list_new ();
1782 info->mail_op = g_object_ref (self);
1783 info->poke_all = poke_all;
1784 info->interactive = interactive;
1785 info->account_name = g_strdup (account_name);
1786 info->callback = callback;
1787 info->user_data = user_data;
1788 info->retrieve_all_cb = retrieve_all_cb;
1790 /* Set account busy */
1791 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1792 modest_mail_operation_notify_start (self);
1794 /* notify about the start of the operation */
1795 state = modest_mail_operation_clone_state (self);
1799 /* Start notifying progress */
1800 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1801 g_slice_free (ModestMailOperationState, state);
1803 /* Get all folders and continue in the callback */
1804 folders = tny_simple_list_new ();
1805 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1806 folders, NULL, FALSE,
1807 recurse_folders_async_cb,
1809 g_object_unref (folders);
1811 g_object_unref (priv->account);
1816 * Used to notify the queue from the main
1817 * loop. We call it inside an idle call to achieve that
1820 idle_notify_queue (gpointer data)
1822 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1824 gdk_threads_enter ();
1825 modest_mail_operation_notify_end (mail_op);
1826 gdk_threads_leave ();
1827 g_object_unref (mail_op);
1833 compare_headers_by_date (gconstpointer a,
1836 TnyHeader **header1, **header2;
1837 time_t sent1, sent2;
1839 header1 = (TnyHeader **) a;
1840 header2 = (TnyHeader **) b;
1842 sent1 = tny_header_get_date_sent (*header1);
1843 sent2 = tny_header_get_date_sent (*header2);
1845 /* We want the most recent ones (greater time_t) at the
1854 /* ******************************************************************* */
1855 /* ************************** STORE ACTIONS ************************* */
1856 /* ******************************************************************* */
1859 ModestMailOperation *mail_op;
1860 CreateFolderUserCallback callback;
1866 create_folder_cb (TnyFolderStore *parent_folder,
1868 TnyFolder *new_folder,
1872 ModestMailOperationPrivate *priv;
1873 CreateFolderInfo *info;
1875 info = (CreateFolderInfo *) user_data;
1876 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1878 if (canceled || err) {
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1881 priv->error = g_error_copy (err);
1883 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1884 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1887 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1890 /* The user will unref the new_folder */
1892 info->callback (info->mail_op, parent_folder,
1893 new_folder, info->user_data);
1895 /* Notify about operation end */
1896 modest_mail_operation_notify_end (info->mail_op);
1899 g_object_unref (info->mail_op);
1900 g_slice_free (CreateFolderInfo, info);
1904 modest_mail_operation_create_folder (ModestMailOperation *self,
1905 TnyFolderStore *parent,
1907 CreateFolderUserCallback callback,
1910 ModestMailOperationPrivate *priv;
1912 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1913 g_return_if_fail (name);
1915 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1916 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1917 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1918 g_object_ref (parent) :
1919 modest_tny_folder_get_account (TNY_FOLDER (parent));
1921 /* Check for already existing folder */
1922 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1923 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1924 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1925 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1926 _CS("ckdg_ib_folder_already_exists"));
1930 if (TNY_IS_FOLDER (parent)) {
1931 /* Check folder rules */
1932 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1933 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1934 /* Set status failed and set an error */
1935 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1936 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1937 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1938 _("mail_in_ui_folder_create_error"));
1942 if (!strcmp (name, " ") || strchr (name, '/')) {
1943 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1944 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1945 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1946 _("mail_in_ui_folder_create_error"));
1950 CreateFolderInfo *info;
1952 info = g_slice_new0 (CreateFolderInfo);
1953 info->mail_op = g_object_ref (self);
1954 info->callback = callback;
1955 info->user_data = user_data;
1957 modest_mail_operation_notify_start (self);
1959 /* Create the folder */
1960 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1963 /* Call the user callback anyway */
1965 callback (self, parent, NULL, user_data);
1966 /* Notify about operation end */
1967 modest_mail_operation_notify_end (self);
1972 modest_mail_operation_remove_folder (ModestMailOperation *self,
1974 gboolean remove_to_trash)
1976 ModestMailOperationPrivate *priv;
1977 ModestTnyFolderRules rules;
1979 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1980 g_return_if_fail (TNY_IS_FOLDER (folder));
1982 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1984 /* Check folder rules */
1985 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1986 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1987 /* Set status failed and set an error */
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1990 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1991 _("mail_in_ui_folder_delete_error"));
1995 /* Get the account */
1996 priv->account = modest_tny_folder_get_account (folder);
1997 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1999 /* Delete folder or move to trash */
2000 if (remove_to_trash) {
2001 TnyFolder *trash_folder = NULL;
2002 trash_folder = modest_tny_account_get_special_folder (priv->account,
2003 TNY_FOLDER_TYPE_TRASH);
2004 /* TODO: error_handling */
2006 modest_mail_operation_notify_start (self);
2007 modest_mail_operation_xfer_folder (self, folder,
2008 TNY_FOLDER_STORE (trash_folder),
2010 g_object_unref (trash_folder);
2012 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2015 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2017 modest_mail_operation_notify_start (self);
2018 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2019 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2022 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2024 g_object_unref (parent);
2026 g_warning ("%s: could not get parent folder", __FUNCTION__);
2030 /* Notify about operation end */
2031 modest_mail_operation_notify_end (self);
2035 transfer_folder_status_cb (GObject *obj,
2039 ModestMailOperation *self;
2040 ModestMailOperationPrivate *priv;
2041 ModestMailOperationState *state;
2042 XFerFolderAsyncHelper *helper;
2044 g_return_if_fail (status != NULL);
2046 /* Show only the status information we want */
2047 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2050 helper = (XFerFolderAsyncHelper *) user_data;
2051 g_return_if_fail (helper != NULL);
2053 self = helper->mail_op;
2054 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2056 priv->done = status->position;
2057 priv->total = status->of_total;
2059 state = modest_mail_operation_clone_state (self);
2061 /* This is not a GDK lock because we are a Tinymail callback
2062 * which is already GDK locked by Tinymail */
2064 /* no gdk_threads_enter (), CHECKED */
2066 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2068 /* no gdk_threads_leave (), CHECKED */
2070 g_slice_free (ModestMailOperationState, state);
2075 transfer_folder_cb (TnyFolder *folder,
2077 TnyFolderStore *into,
2078 TnyFolder *new_folder,
2082 XFerFolderAsyncHelper *helper;
2083 ModestMailOperation *self = NULL;
2084 ModestMailOperationPrivate *priv = NULL;
2086 helper = (XFerFolderAsyncHelper *) user_data;
2087 g_return_if_fail (helper != NULL);
2089 self = helper->mail_op;
2090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2093 priv->error = g_error_copy (err);
2095 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2096 } else if (cancelled) {
2097 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2098 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2099 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2100 _("Transference of %s was cancelled."),
2101 tny_folder_get_name (folder));
2104 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2107 /* Notify about operation end */
2108 modest_mail_operation_notify_end (self);
2110 /* If user defined callback function was defined, call it */
2111 if (helper->user_callback) {
2113 /* This is not a GDK lock because we are a Tinymail callback
2114 * which is already GDK locked by Tinymail */
2116 /* no gdk_threads_enter (), CHECKED */
2117 helper->user_callback (self, new_folder, helper->user_data);
2118 /* no gdk_threads_leave () , CHECKED */
2122 g_object_unref (helper->mail_op);
2123 g_slice_free (XFerFolderAsyncHelper, helper);
2128 * This function checks if the new name is a valid name for our local
2129 * folders account. The new name could not be the same than then name
2130 * of any of the mandatory local folders
2132 * We can not rely on tinymail because tinymail does not check the
2133 * name of the virtual folders that the account could have in the case
2134 * that we're doing a rename (because it directly calls Camel which
2135 * knows nothing about our virtual folders).
2137 * In the case of an actual copy/move (i.e. move/copy a folder between
2138 * accounts) tinymail uses the tny_folder_store_create_account which
2139 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2140 * checks the new name of the folder, so this call in that case
2141 * wouldn't be needed. *But* NOTE that if tinymail changes its
2142 * implementation (if folder transfers within the same account is no
2143 * longer implemented as a rename) this call will allow Modest to work
2146 * If the new name is not valid, this function will set the status to
2147 * failed and will set also an error in the mail operation
2150 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2151 TnyFolderStore *into,
2152 const gchar *new_name)
2154 if (TNY_IS_ACCOUNT (into) &&
2155 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2156 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2158 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2159 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2160 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2161 _CS("ckdg_ib_folder_already_exists"));
2168 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2170 TnyFolderStore *parent,
2171 gboolean delete_original,
2172 XferFolderAsyncUserCallback user_callback,
2175 ModestMailOperationPrivate *priv = NULL;
2176 ModestTnyFolderRules parent_rules = 0, rules;
2177 XFerFolderAsyncHelper *helper = NULL;
2178 const gchar *folder_name = NULL;
2179 const gchar *error_msg;
2181 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2182 g_return_if_fail (TNY_IS_FOLDER (folder));
2183 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2185 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2186 folder_name = tny_folder_get_name (folder);
2188 /* Set the error msg */
2189 error_msg = _("mail_in_ui_folder_move_target_error");
2191 /* Get account and set it into mail_operation */
2192 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2193 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2194 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2196 /* Get folder rules */
2197 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2198 if (TNY_IS_FOLDER (parent))
2199 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2201 /* Apply operation constraints */
2202 if ((gpointer) parent == (gpointer) folder ||
2203 (!TNY_IS_FOLDER_STORE (parent)) ||
2204 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2207 } else if (TNY_IS_FOLDER (parent) &&
2208 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2212 } else if (TNY_IS_FOLDER (parent) &&
2213 TNY_IS_FOLDER_STORE (folder) &&
2214 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2215 TNY_FOLDER_STORE (folder))) {
2216 /* Do not move a parent into a child */
2218 } else if (TNY_IS_FOLDER_STORE (parent) &&
2219 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2220 /* Check that the new folder name is not used by any
2223 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2224 /* Check that the new folder name is not used by any
2225 special local folder */
2228 /* Create the helper */
2229 helper = g_slice_new0 (XFerFolderAsyncHelper);
2230 helper->mail_op = g_object_ref (self);
2231 helper->user_callback = user_callback;
2232 helper->user_data = user_data;
2234 /* Move/Copy folder */
2235 modest_mail_operation_notify_start (self);
2236 tny_folder_copy_async (folder,
2238 tny_folder_get_name (folder),
2241 transfer_folder_status_cb,
2247 /* Set status failed and set an error */
2248 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2249 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2250 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2253 /* Call the user callback if exists */
2255 user_callback (self, NULL, user_data);
2257 /* Notify the queue */
2258 modest_mail_operation_notify_end (self);
2262 modest_mail_operation_rename_folder (ModestMailOperation *self,
2265 XferFolderAsyncUserCallback user_callback,
2268 ModestMailOperationPrivate *priv;
2269 ModestTnyFolderRules rules;
2270 XFerFolderAsyncHelper *helper;
2272 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2273 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2274 g_return_if_fail (name);
2276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2278 /* Get account and set it into mail_operation */
2279 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2280 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2282 /* Check folder rules */
2283 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2284 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2286 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2289 TnyFolderStore *into;
2291 into = tny_folder_get_folder_store (folder);
2293 /* Check that the new folder name is not used by any
2294 special local folder */
2295 if (new_name_valid_if_local_account (priv, into, name)) {
2296 /* Create the helper */
2297 helper = g_slice_new0 (XFerFolderAsyncHelper);
2298 helper->mail_op = g_object_ref(self);
2299 helper->user_callback = user_callback;
2300 helper->user_data = user_data;
2302 /* Rename. Camel handles folder subscription/unsubscription */
2303 modest_mail_operation_notify_start (self);
2304 tny_folder_copy_async (folder, into, name, TRUE,
2306 transfer_folder_status_cb,
2308 g_object_unref (into);
2310 g_object_unref (into);
2317 /* Set status failed and set an error */
2318 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2320 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2321 _("FIXME: unable to rename"));
2324 user_callback (self, NULL, user_data);
2326 /* Notify about operation end */
2327 modest_mail_operation_notify_end (self);
2330 /* ******************************************************************* */
2331 /* ************************** MSG ACTIONS ************************* */
2332 /* ******************************************************************* */
2335 modest_mail_operation_get_msg (ModestMailOperation *self,
2337 gboolean progress_feedback,
2338 GetMsgAsyncUserCallback user_callback,
2341 GetMsgInfo *helper = NULL;
2343 ModestMailOperationPrivate *priv;
2345 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2346 g_return_if_fail (TNY_IS_HEADER (header));
2348 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2349 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2353 /* Check memory low */
2354 if (_check_memory_low (self)) {
2356 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2357 modest_mail_operation_notify_end (self);
2361 /* Get account and set it into mail_operation */
2362 folder = tny_header_get_folder (header);
2363 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2365 /* Check for cached messages */
2366 if (progress_feedback) {
2367 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2368 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2370 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2372 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2375 /* Create the helper */
2376 helper = g_slice_new0 (GetMsgInfo);
2377 helper->header = g_object_ref (header);
2378 helper->mail_op = g_object_ref (self);
2379 helper->user_callback = user_callback;
2380 helper->user_data = user_data;
2381 helper->destroy_notify = NULL;
2382 helper->last_total_bytes = 0;
2383 helper->sum_total_bytes = 0;
2384 helper->total_bytes = tny_header_get_message_size (header);
2385 helper->more_msgs = NULL;
2387 modest_mail_operation_notify_start (self);
2389 /* notify about the start of the operation */
2390 ModestMailOperationState *state;
2391 state = modest_mail_operation_clone_state (self);
2394 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2396 g_slice_free (ModestMailOperationState, state);
2398 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2400 g_object_unref (G_OBJECT (folder));
2404 get_msg_status_cb (GObject *obj,
2408 GetMsgInfo *helper = NULL;
2410 g_return_if_fail (status != NULL);
2412 /* Show only the status information we want */
2413 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2416 helper = (GetMsgInfo *) user_data;
2417 g_return_if_fail (helper != NULL);
2419 /* Notify progress */
2420 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2421 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2425 get_msg_async_cb (TnyFolder *folder,
2431 GetMsgInfo *info = NULL;
2432 ModestMailOperationPrivate *priv = NULL;
2435 info = (GetMsgInfo *) user_data;
2437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2440 if (info->more_msgs) {
2441 tny_iterator_next (info->more_msgs);
2442 finished = (tny_iterator_is_done (info->more_msgs));
2444 finished = (priv->done == priv->total) ? TRUE : FALSE;
2447 /* If canceled by the user, ignore the error given by Tinymail */
2451 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2453 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2455 priv->error = g_error_copy ((const GError *) err);
2456 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2459 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2460 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2463 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2464 /* Set the success status before calling the user callback */
2465 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2469 /* Call the user callback */
2470 if (info->user_callback)
2471 info->user_callback (info->mail_op, info->header, canceled,
2472 msg, err, info->user_data);
2474 /* Notify about operation end if this is the last callback */
2476 /* Free user data */
2477 if (info->destroy_notify)
2478 info->destroy_notify (info->user_data);
2480 /* Notify about operation end */
2481 modest_mail_operation_notify_end (info->mail_op);
2484 if (info->more_msgs)
2485 g_object_unref (info->more_msgs);
2486 g_object_unref (info->header);
2487 g_object_unref (info->mail_op);
2488 g_slice_free (GetMsgInfo, info);
2489 } else if (info->more_msgs) {
2490 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2491 TnyFolder *folder = tny_header_get_folder (header);
2493 g_object_unref (info->header);
2494 info->header = g_object_ref (header);
2496 /* Retrieve the next message */
2497 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2499 g_object_unref (header);
2500 g_object_unref (folder);
2502 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2507 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2508 TnyList *header_list,
2509 GetMsgAsyncUserCallback user_callback,
2511 GDestroyNotify notify)
2513 ModestMailOperationPrivate *priv = NULL;
2515 TnyIterator *iter = NULL;
2516 gboolean has_uncached_messages;
2518 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2520 /* Init mail operation */
2521 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2522 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2524 priv->total = tny_list_get_length(header_list);
2526 /* Check memory low */
2527 if (_check_memory_low (self)) {
2528 if (user_callback) {
2529 TnyHeader *header = NULL;
2532 if (tny_list_get_length (header_list) > 0) {
2533 iter = tny_list_create_iterator (header_list);
2534 header = (TnyHeader *) tny_iterator_get_current (iter);
2535 g_object_unref (iter);
2537 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2539 g_object_unref (header);
2543 /* Notify about operation end */
2544 modest_mail_operation_notify_end (self);
2548 /* Check uncached messages */
2549 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2550 !has_uncached_messages && !tny_iterator_is_done (iter);
2551 tny_iterator_next (iter)) {
2554 header = (TnyHeader *) tny_iterator_get_current (iter);
2555 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2556 has_uncached_messages = TRUE;
2557 g_object_unref (header);
2559 g_object_unref (iter);
2560 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2562 /* Get account and set it into mail_operation */
2563 if (tny_list_get_length (header_list) >= 1) {
2564 TnyIterator *iterator = tny_list_create_iterator (header_list);
2565 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2567 TnyFolder *folder = tny_header_get_folder (header);
2569 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2570 g_object_unref (folder);
2572 g_object_unref (header);
2574 g_object_unref (iterator);
2577 msg_list_size = compute_message_list_size (header_list, 0);
2579 modest_mail_operation_notify_start (self);
2580 iter = tny_list_create_iterator (header_list);
2581 if (!tny_iterator_is_done (iter)) {
2582 /* notify about the start of the operation */
2583 ModestMailOperationState *state;
2584 state = modest_mail_operation_clone_state (self);
2587 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2590 GetMsgInfo *msg_info = NULL;
2591 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2592 TnyFolder *folder = tny_header_get_folder (header);
2594 /* Create the message info */
2595 msg_info = g_slice_new0 (GetMsgInfo);
2596 msg_info->mail_op = g_object_ref (self);
2597 msg_info->header = g_object_ref (header);
2598 msg_info->more_msgs = g_object_ref (iter);
2599 msg_info->user_callback = user_callback;
2600 msg_info->user_data = user_data;
2601 msg_info->destroy_notify = notify;
2602 msg_info->last_total_bytes = 0;
2603 msg_info->sum_total_bytes = 0;
2604 msg_info->total_bytes = msg_list_size;
2606 /* The callback will call it per each header */
2607 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2609 /* Free and go on */
2610 g_object_unref (header);
2611 g_object_unref (folder);
2612 g_slice_free (ModestMailOperationState, state);
2614 g_object_unref (iter);
2619 remove_msgs_async_cb (TnyFolder *folder,
2624 gboolean expunge, leave_on_server;
2625 const gchar *account_name;
2626 TnyAccount *account;
2627 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2628 ModestMailOperation *self;
2629 ModestMailOperationPrivate *priv;
2630 ModestProtocolRegistry *protocol_registry;
2632 self = (ModestMailOperation *) user_data;
2633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2634 protocol_registry = modest_runtime_get_protocol_registry ();
2636 if (canceled || err) {
2637 /* If canceled by the user, ignore the error given by Tinymail */
2639 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2641 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2642 priv->error = g_error_copy ((const GError *) err);
2643 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2646 modest_mail_operation_notify_end (self);
2647 g_object_unref (self);
2651 account = tny_folder_get_account (folder);
2652 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2654 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2656 account_proto = modest_tny_account_get_protocol_type (account);
2657 g_object_unref (account);
2659 if (( (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) && !leave_on_server) ||
2660 modest_tny_folder_is_remote_folder (folder) == FALSE))
2666 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2671 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2673 gboolean remove_to_trash /*ignored*/)
2675 TnyFolder *folder = NULL;
2676 ModestMailOperationPrivate *priv;
2677 TnyIterator *iter = NULL;
2678 TnyHeader *header = NULL;
2679 TnyList *remove_headers = NULL;
2680 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2682 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2683 g_return_if_fail (TNY_IS_LIST (headers));
2685 if (remove_to_trash)
2686 g_warning ("remove to trash is not implemented");
2688 if (tny_list_get_length(headers) == 0) {
2689 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2690 goto cleanup; /* nothing to do */
2693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2694 remove_headers = g_object_ref(headers);
2696 /* Get folder from first header and sync it */
2697 iter = tny_list_create_iterator (headers);
2698 header = TNY_HEADER (tny_iterator_get_current (iter));
2700 folder = tny_header_get_folder (header);
2701 if (!TNY_IS_FOLDER(folder)) {
2702 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2706 /* Don't remove messages that are being sent */
2707 if (modest_tny_folder_is_local_folder (folder)) {
2708 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2710 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2711 TnyTransportAccount *traccount = NULL;
2712 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2713 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2715 ModestTnySendQueueStatus status;
2716 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2718 if (TNY_IS_SEND_QUEUE (send_queue)) {
2719 TnyIterator *iter = tny_list_create_iterator(headers);
2720 g_object_unref(remove_headers);
2721 remove_headers = TNY_LIST(tny_simple_list_new());
2722 while (!tny_iterator_is_done(iter)) {
2724 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2725 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2726 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2727 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2728 tny_list_append(remove_headers, G_OBJECT(hdr));
2730 g_object_unref(hdr);
2732 tny_iterator_next(iter);
2734 g_object_unref(iter);
2736 g_object_unref(traccount);
2740 /* Get account and set it into mail_operation */
2741 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2742 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2745 /* remove message from folder */
2746 modest_mail_operation_notify_start (self);
2747 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2748 NULL, g_object_ref (self));
2752 g_object_unref (remove_headers);
2754 g_object_unref (header);
2756 g_object_unref (iter);
2758 g_object_unref (folder);
2762 notify_progress_of_multiple_messages (ModestMailOperation *self,
2764 gint *last_total_bytes,
2765 gint *sum_total_bytes,
2767 gboolean increment_done)
2769 ModestMailOperationPrivate *priv;
2770 ModestMailOperationState *state;
2771 gboolean is_num_bytes = FALSE;
2773 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2775 /* We know that tinymail sends us information about
2776 * transferred bytes with this particular message
2778 if (status->message)
2779 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2781 state = modest_mail_operation_clone_state (self);
2782 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2783 /* We know that we're in a different message when the
2784 total number of bytes to transfer is different. Of
2785 course it could fail if we're transferring messages
2786 of the same size, but this is a workarround */
2787 if (status->of_total != *last_total_bytes) {
2788 /* We need to increment the done when there is
2789 no information about each individual
2790 message, we need to do this in message
2791 transfers, and we don't do it for getting
2795 *sum_total_bytes += *last_total_bytes;
2796 *last_total_bytes = status->of_total;
2798 state->bytes_done += status->position + *sum_total_bytes;
2799 state->bytes_total = total_bytes;
2801 /* Notify the status change. Only notify about changes
2802 referred to bytes */
2803 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2807 g_slice_free (ModestMailOperationState, state);
2811 transfer_msgs_status_cb (GObject *obj,
2815 XFerMsgsAsyncHelper *helper;
2817 g_return_if_fail (status != NULL);
2819 /* Show only the status information we want */
2820 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2823 helper = (XFerMsgsAsyncHelper *) user_data;
2824 g_return_if_fail (helper != NULL);
2826 /* Notify progress */
2827 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2828 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2832 transfer_msgs_sync_folder_cb (TnyFolder *self,
2837 XFerMsgsAsyncHelper *helper;
2838 /* We don't care here about the results of the
2840 helper = (XFerMsgsAsyncHelper *) user_data;
2842 /* Notify about operation end */
2843 modest_mail_operation_notify_end (helper->mail_op);
2845 /* If user defined callback function was defined, call it */
2846 if (helper->user_callback)
2847 helper->user_callback (helper->mail_op, helper->user_data);
2850 if (helper->more_msgs)
2851 g_object_unref (helper->more_msgs);
2852 if (helper->headers)
2853 g_object_unref (helper->headers);
2854 if (helper->dest_folder)
2855 g_object_unref (helper->dest_folder);
2856 if (helper->mail_op)
2857 g_object_unref (helper->mail_op);
2858 g_slice_free (XFerMsgsAsyncHelper, helper);
2862 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2864 XFerMsgsAsyncHelper *helper;
2865 ModestMailOperation *self;
2866 ModestMailOperationPrivate *priv;
2867 gboolean finished = TRUE;
2869 helper = (XFerMsgsAsyncHelper *) user_data;
2870 self = helper->mail_op;
2872 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2875 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2877 priv->error = g_error_copy (err);
2879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2880 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2881 if (helper->more_msgs) {
2882 /* We'll transfer the next message in the list */
2883 tny_iterator_next (helper->more_msgs);
2884 if (!tny_iterator_is_done (helper->more_msgs)) {
2885 GObject *next_header;
2886 g_object_unref (helper->headers);
2887 helper->headers = tny_simple_list_new ();
2888 next_header = tny_iterator_get_current (helper->more_msgs);
2889 tny_list_append (helper->headers, next_header);
2890 g_object_unref (next_header);
2896 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2901 /* Synchronize the source folder contents. This should
2902 be done by tinymail but the camel_folder_sync it's
2903 actually disabled in transfer_msgs_thread_clean
2904 because it's supposed to cause hangs */
2905 tny_folder_sync_async (folder, helper->delete,
2906 transfer_msgs_sync_folder_cb,
2909 /* Transfer more messages */
2910 tny_folder_transfer_msgs_async (folder,
2912 helper->dest_folder,
2915 transfer_msgs_status_cb,
2920 /* Computes the size of the messages the headers in the list belongs
2921 to. If num_elements is different from 0 then it only takes into
2922 account the first num_elements for the calculation */
2924 compute_message_list_size (TnyList *headers,
2928 guint size = 0, element = 0;
2930 /* If num_elements is not valid then take all into account */
2931 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2932 num_elements = tny_list_get_length (headers);
2934 iter = tny_list_create_iterator (headers);
2935 while (!tny_iterator_is_done (iter) && element < num_elements) {
2936 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2937 size += tny_header_get_message_size (header);
2938 g_object_unref (header);
2939 tny_iterator_next (iter);
2942 g_object_unref (iter);
2948 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2951 gboolean delete_original,
2952 XferMsgsAsyncUserCallback user_callback,
2955 ModestMailOperationPrivate *priv = NULL;
2956 TnyIterator *iter = NULL;
2957 TnyFolder *src_folder = NULL;
2958 XFerMsgsAsyncHelper *helper = NULL;
2959 TnyHeader *header = NULL;
2960 ModestTnyFolderRules rules = 0;
2961 TnyAccount *dst_account = NULL;
2962 gboolean leave_on_server;
2963 ModestMailOperationState *state;
2964 ModestProtocolRegistry *protocol_registry;
2965 ModestProtocolType account_protocol;
2967 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2968 g_return_if_fail (headers && TNY_IS_LIST (headers));
2969 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2971 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2972 protocol_registry = modest_runtime_get_protocol_registry ();
2974 priv->total = tny_list_get_length (headers);
2976 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2977 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2979 /* Apply folder rules */
2980 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2981 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2982 /* Set status failed and set an error */
2983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2984 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2985 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2986 _CS("ckct_ib_unable_to_paste_here"));
2987 /* Notify the queue */
2988 modest_mail_operation_notify_end (self);
2992 /* Get source folder */
2993 iter = tny_list_create_iterator (headers);
2994 header = TNY_HEADER (tny_iterator_get_current (iter));
2996 src_folder = tny_header_get_folder (header);
2997 g_object_unref (header);
2999 g_object_unref (iter);
3001 if (src_folder == NULL) {
3002 /* Notify the queue */
3003 modest_mail_operation_notify_end (self);
3005 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3010 /* Check folder source and destination */
3011 if (src_folder == folder) {
3012 /* Set status failed and set an error */
3013 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3014 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3015 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3016 _("mail_in_ui_folder_copy_target_error"));
3018 /* Notify the queue */
3019 modest_mail_operation_notify_end (self);
3022 g_object_unref (src_folder);
3026 /* Create the helper */
3027 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3028 helper->mail_op = g_object_ref(self);
3029 helper->dest_folder = g_object_ref(folder);
3030 helper->user_callback = user_callback;
3031 helper->user_data = user_data;
3032 helper->last_total_bytes = 0;
3033 helper->sum_total_bytes = 0;
3034 helper->total_bytes = compute_message_list_size (headers, 0);
3036 /* Get account and set it into mail_operation */
3037 priv->account = modest_tny_folder_get_account (src_folder);
3038 dst_account = modest_tny_folder_get_account (folder);
3040 if (priv->account == dst_account) {
3041 /* Transfer all messages at once using the fast
3042 * method. Note that depending on the server this
3043 * might not be that fast, and might not be
3044 * user-cancellable either */
3045 helper->headers = g_object_ref (headers);
3046 helper->more_msgs = NULL;
3048 /* Transfer messages one by one so the user can cancel
3051 helper->headers = tny_simple_list_new ();
3052 helper->more_msgs = tny_list_create_iterator (headers);
3053 hdr = tny_iterator_get_current (helper->more_msgs);
3054 tny_list_append (helper->headers, hdr);
3055 g_object_unref (hdr);
3058 /* If leave_on_server is set to TRUE then don't use
3059 delete_original, we always pass FALSE. This is because
3060 otherwise tinymail will try to sync the source folder and
3061 this could cause an error if we're offline while
3062 transferring an already downloaded message from a POP
3064 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3065 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3066 const gchar *account_name;
3068 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3069 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3072 leave_on_server = FALSE;
3075 /* Do not delete messages if leave on server is TRUE */
3076 helper->delete = (leave_on_server) ? FALSE : delete_original;
3078 modest_mail_operation_notify_start (self);
3080 /* Start notifying progress */
3081 state = modest_mail_operation_clone_state (self);
3084 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3085 g_slice_free (ModestMailOperationState, state);
3087 tny_folder_transfer_msgs_async (src_folder,
3092 transfer_msgs_status_cb,
3094 g_object_unref (src_folder);
3095 g_object_unref (dst_account);
3100 on_refresh_folder (TnyFolder *folder,
3105 RefreshAsyncHelper *helper = NULL;
3106 ModestMailOperation *self = NULL;
3107 ModestMailOperationPrivate *priv = NULL;
3109 helper = (RefreshAsyncHelper *) user_data;
3110 self = helper->mail_op;
3111 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3113 g_return_if_fail(priv!=NULL);
3116 priv->error = g_error_copy (error);
3117 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3122 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3123 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3124 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3125 _("Error trying to refresh the contents of %s"),
3126 tny_folder_get_name (folder));
3130 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3133 /* Call user defined callback, if it exists */
3134 if (helper->user_callback) {
3136 /* This is not a GDK lock because we are a Tinymail callback and
3137 * Tinymail already acquires the Gdk lock */
3138 helper->user_callback (self, folder, helper->user_data);
3142 g_slice_free (RefreshAsyncHelper, helper);
3144 /* Notify about operation end */
3145 modest_mail_operation_notify_end (self);
3146 g_object_unref(self);
3150 on_refresh_folder_status_update (GObject *obj,
3154 RefreshAsyncHelper *helper = NULL;
3155 ModestMailOperation *self = NULL;
3156 ModestMailOperationPrivate *priv = NULL;
3157 ModestMailOperationState *state;
3159 g_return_if_fail (user_data != NULL);
3160 g_return_if_fail (status != NULL);
3162 /* Show only the status information we want */
3163 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3166 helper = (RefreshAsyncHelper *) user_data;
3167 self = helper->mail_op;
3168 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3170 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3172 priv->done = status->position;
3173 priv->total = status->of_total;
3175 state = modest_mail_operation_clone_state (self);
3177 /* This is not a GDK lock because we are a Tinymail callback and
3178 * Tinymail already acquires the Gdk lock */
3179 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3181 g_slice_free (ModestMailOperationState, state);
3185 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3187 RefreshAsyncUserCallback user_callback,
3190 ModestMailOperationPrivate *priv = NULL;
3191 RefreshAsyncHelper *helper = NULL;
3193 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3195 /* Check memory low */
3196 if (_check_memory_low (self)) {
3198 user_callback (self, folder, user_data);
3199 /* Notify about operation end */
3200 modest_mail_operation_notify_end (self);
3204 /* Get account and set it into mail_operation */
3205 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3206 priv->account = modest_tny_folder_get_account (folder);
3207 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3209 /* Create the helper */
3210 helper = g_slice_new0 (RefreshAsyncHelper);
3211 helper->mail_op = g_object_ref(self);
3212 helper->user_callback = user_callback;
3213 helper->user_data = user_data;
3215 modest_mail_operation_notify_start (self);
3217 /* notify that the operation was started */
3218 ModestMailOperationState *state;
3219 state = modest_mail_operation_clone_state (self);
3222 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3224 g_slice_free (ModestMailOperationState, state);
3226 tny_folder_refresh_async (folder,
3228 on_refresh_folder_status_update,
3233 run_queue_stop (ModestTnySendQueue *queue,
3234 ModestMailOperation *self)
3236 ModestMailOperationPrivate *priv;
3238 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3239 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3242 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3244 modest_mail_operation_notify_end (self);
3245 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3246 g_object_unref (self);
3250 modest_mail_operation_run_queue (ModestMailOperation *self,
3251 ModestTnySendQueue *queue)
3253 ModestMailOperationPrivate *priv;
3255 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3256 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3259 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3260 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3261 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3263 modest_mail_operation_notify_start (self);
3264 g_object_ref (self);
3265 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3269 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3271 ModestMailOperation *self = (ModestMailOperation *) userdata;
3272 ModestMailOperationPrivate *priv;
3274 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3275 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3278 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3280 modest_mail_operation_notify_end (self);
3281 g_object_unref (self);
3285 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3287 ModestMailOperationPrivate *priv;
3289 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3290 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3293 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3295 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3296 priv->account = NULL;
3297 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3299 modest_mail_operation_notify_start (self);
3300 g_object_ref (self);
3301 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3305 sync_folder_finish_callback (TnyFolder *self,
3311 ModestMailOperation *mail_op;
3312 ModestMailOperationPrivate *priv;
3314 mail_op = (ModestMailOperation *) user_data;
3315 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3317 /* If canceled by the user, ignore the error given by Tinymail */
3319 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3321 /* If the operation was a sync then the status is
3322 failed, but if it's part of another operation then
3323 just set it as finished with errors */
3324 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3325 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3327 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3328 priv->error = g_error_copy ((const GError *) err);
3329 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3331 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3334 modest_mail_operation_notify_end (mail_op);
3335 g_object_unref (mail_op);
3339 modest_mail_operation_sync_folder (ModestMailOperation *self,
3340 TnyFolder *folder, gboolean expunge)
3342 ModestMailOperationPrivate *priv;
3344 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3345 g_return_if_fail (TNY_IS_FOLDER (folder));
3346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3348 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3349 priv->account = modest_tny_folder_get_account (folder);
3350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3352 modest_mail_operation_notify_start (self);
3353 g_object_ref (self);
3354 tny_folder_sync_async (folder, expunge,
3355 (TnyFolderCallback) sync_folder_finish_callback,
3360 modest_mail_operation_notify_start (ModestMailOperation *self)
3362 ModestMailOperationPrivate *priv = NULL;
3364 g_return_if_fail (self);
3366 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3368 /* Ensure that all the fields are filled correctly */
3369 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3371 /* Notify the observers about the mail operation. We do not
3372 wrapp this emission because we assume that this function is
3373 always called from within the main lock */
3374 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3379 * It's used by the mail operation queue to notify the observers
3380 * attached to that signal that the operation finished. We need to use
3381 * that because tinymail does not give us the progress of a given
3382 * operation when it finishes (it directly calls the operation
3386 modest_mail_operation_notify_end (ModestMailOperation *self)
3388 ModestMailOperationPrivate *priv = NULL;
3390 g_return_if_fail (self);
3392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3394 /* Notify the observers about the mail operation end. We do
3395 not wrapp this emission because we assume that this
3396 function is always called from within the main lock */
3397 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3399 /* Remove the error user data */
3400 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3401 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3405 modest_mail_operation_get_account (ModestMailOperation *self)
3407 ModestMailOperationPrivate *priv = NULL;
3409 g_return_val_if_fail (self, NULL);
3411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3413 return (priv->account) ? g_object_ref (priv->account) : NULL;
3417 modest_mail_operation_noop (ModestMailOperation *self)
3419 ModestMailOperationPrivate *priv = NULL;
3421 g_return_if_fail (self);
3423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3424 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3425 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3429 /* This mail operation does nothing actually */
3430 modest_mail_operation_notify_start (self);
3431 modest_mail_operation_notify_end (self);
3436 modest_mail_operation_to_string (ModestMailOperation *self)
3438 const gchar *type, *status, *account_id;
3439 ModestMailOperationPrivate *priv = NULL;
3441 g_return_val_if_fail (self, NULL);
3443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3445 /* new operations don't have anything interesting */
3446 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3447 return g_strdup_printf ("%p <new operation>", self);
3449 switch (priv->op_type) {
3450 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3451 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3452 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3453 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3454 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3455 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3456 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3457 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3458 default: type = "UNEXPECTED"; break;
3461 switch (priv->status) {
3462 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3463 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3464 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3465 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3466 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3467 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3468 default: status= "UNEXPECTED"; break;
3471 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3473 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3474 priv->done, priv->total,
3475 priv->error && priv->error->message ? priv->error->message : "");
3479 * Once the mail operations were objects this will be no longer
3480 * needed. I don't like it, but we need it for the moment
3483 _check_memory_low (ModestMailOperation *mail_op)
3485 if (modest_platform_check_memory_low (NULL, FALSE)) {
3486 ModestMailOperationPrivate *priv;
3488 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3489 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3490 g_set_error (&(priv->error),
3491 MODEST_MAIL_OPERATION_ERROR,
3492 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3493 "Not enough memory to complete the operation");