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);
100 static guint compute_message_array_size (GPtrArray *headers);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 static gboolean _check_memory_low (ModestMailOperation *mail_op);
112 enum _ModestMailOperationSignals
114 PROGRESS_CHANGED_SIGNAL,
115 OPERATION_STARTED_SIGNAL,
116 OPERATION_FINISHED_SIGNAL,
120 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
121 struct _ModestMailOperationPrivate {
127 ErrorCheckingUserCallback error_checking;
128 gpointer error_checking_user_data;
129 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
130 ModestMailOperationStatus status;
131 ModestMailOperationTypeOperation op_type;
134 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
135 MODEST_TYPE_MAIL_OPERATION, \
136 ModestMailOperationPrivate))
138 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
139 priv->status = new_status;\
144 GetMsgAsyncUserCallback user_callback;
146 TnyIterator *more_msgs;
148 ModestMailOperation *mail_op;
149 GDestroyNotify destroy_notify;
150 gint last_total_bytes;
151 gint sum_total_bytes;
155 typedef struct _RefreshAsyncHelper {
156 ModestMailOperation *mail_op;
157 RefreshAsyncUserCallback user_callback;
159 } RefreshAsyncHelper;
161 typedef struct _XFerMsgsAsyncHelper
163 ModestMailOperation *mail_op;
165 TnyIterator *more_msgs;
166 TnyFolder *dest_folder;
167 XferMsgsAsyncUserCallback user_callback;
170 gint last_total_bytes;
171 gint sum_total_bytes;
173 } XFerMsgsAsyncHelper;
175 typedef struct _XFerFolderAsyncHelper
177 ModestMailOperation *mail_op;
178 XferFolderAsyncUserCallback user_callback;
180 } XFerFolderAsyncHelper;
182 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
186 static void modest_mail_operation_create_msg (ModestMailOperation *self,
187 const gchar *from, const gchar *to,
188 const gchar *cc, const gchar *bcc,
189 const gchar *subject, const gchar *plain_body,
190 const gchar *html_body, const GList *attachments_list,
191 const GList *images_list,
192 TnyHeaderFlags priority_flags,
193 ModestMailOperationCreateMsgCallback callback,
196 static gboolean idle_notify_queue (gpointer data);
199 ModestMailOperation *mail_op;
207 GList *attachments_list;
209 TnyHeaderFlags priority_flags;
210 ModestMailOperationCreateMsgCallback callback;
216 ModestMailOperation *mail_op;
218 ModestMailOperationCreateMsgCallback callback;
223 static GObjectClass *parent_class = NULL;
225 static guint signals[NUM_SIGNALS] = {0};
228 modest_mail_operation_get_type (void)
230 static GType my_type = 0;
232 static const GTypeInfo my_info = {
233 sizeof(ModestMailOperationClass),
234 NULL, /* base init */
235 NULL, /* base finalize */
236 (GClassInitFunc) modest_mail_operation_class_init,
237 NULL, /* class finalize */
238 NULL, /* class data */
239 sizeof(ModestMailOperation),
241 (GInstanceInitFunc) modest_mail_operation_init,
244 my_type = g_type_register_static (G_TYPE_OBJECT,
245 "ModestMailOperation",
252 modest_mail_operation_class_init (ModestMailOperationClass *klass)
254 GObjectClass *gobject_class;
255 gobject_class = (GObjectClass*) klass;
257 parent_class = g_type_class_peek_parent (klass);
258 gobject_class->finalize = modest_mail_operation_finalize;
260 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
263 * ModestMailOperation::progress-changed
264 * @self: the #MailOperation that emits the signal
265 * @user_data: user data set when the signal handler was connected
267 * Emitted when the progress of a mail operation changes
269 signals[PROGRESS_CHANGED_SIGNAL] =
270 g_signal_new ("progress-changed",
271 G_TYPE_FROM_CLASS (gobject_class),
273 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
275 g_cclosure_marshal_VOID__POINTER,
276 G_TYPE_NONE, 1, G_TYPE_POINTER);
280 * This signal is issued whenever a mail operation starts, and
281 * starts mean when the tinymail operation is issued. This
282 * means that it could happen that something wrong happens and
283 * the tinymail function is never called. In this situation a
284 * operation-finished will be issued without any
287 signals[OPERATION_STARTED_SIGNAL] =
288 g_signal_new ("operation-started",
289 G_TYPE_FROM_CLASS (gobject_class),
291 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
293 g_cclosure_marshal_VOID__VOID,
298 * This signal is issued whenever a mail operation
299 * finishes. Note that this signal could be issued without any
300 * previous "operation-started" signal, because this last one
301 * is only issued when the tinymail operation is successfully
304 signals[OPERATION_FINISHED_SIGNAL] =
305 g_signal_new ("operation-finished",
306 G_TYPE_FROM_CLASS (gobject_class),
308 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
310 g_cclosure_marshal_VOID__VOID,
315 modest_mail_operation_init (ModestMailOperation *obj)
317 ModestMailOperationPrivate *priv;
319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
321 priv->account = NULL;
322 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
323 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
328 priv->error_checking = NULL;
329 priv->error_checking_user_data = NULL;
333 modest_mail_operation_finalize (GObject *obj)
335 ModestMailOperationPrivate *priv;
337 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
342 g_error_free (priv->error);
346 g_object_unref (priv->source);
350 g_object_unref (priv->account);
351 priv->account = NULL;
355 G_OBJECT_CLASS(parent_class)->finalize (obj);
359 modest_mail_operation_new (GObject *source)
361 ModestMailOperation *obj;
362 ModestMailOperationPrivate *priv;
364 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
368 priv->source = g_object_ref(source);
374 modest_mail_operation_new_with_error_handling (GObject *source,
375 ErrorCheckingUserCallback error_handler,
377 ErrorCheckingUserDataDestroyer error_handler_destroyer)
379 ModestMailOperation *obj;
380 ModestMailOperationPrivate *priv;
382 obj = modest_mail_operation_new (source);
383 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
385 g_return_val_if_fail (error_handler != NULL, obj);
386 priv->error_checking = error_handler;
387 priv->error_checking_user_data = user_data;
388 priv->error_checking_user_data_destroyer = error_handler_destroyer;
394 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
401 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
403 /* Call the user callback */
404 if (priv->error_checking != NULL)
405 priv->error_checking (self, priv->error_checking_user_data);
409 ModestMailOperationTypeOperation
410 modest_mail_operation_get_type_operation (ModestMailOperation *self)
412 ModestMailOperationPrivate *priv;
414 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
415 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
419 return priv->op_type;
423 modest_mail_operation_is_mine (ModestMailOperation *self,
426 ModestMailOperationPrivate *priv;
428 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
432 if (priv->source == NULL) return FALSE;
434 return priv->source == me;
438 modest_mail_operation_get_source (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
445 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
447 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
451 return (priv->source) ? g_object_ref (priv->source) : NULL;
454 ModestMailOperationStatus
455 modest_mail_operation_get_status (ModestMailOperation *self)
457 ModestMailOperationPrivate *priv;
459 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
460 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
461 MODEST_MAIL_OPERATION_STATUS_INVALID);
463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
465 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
466 return MODEST_MAIL_OPERATION_STATUS_INVALID;
473 modest_mail_operation_get_error (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (self, NULL);
478 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
483 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
491 modest_mail_operation_cancel (ModestMailOperation *self)
493 ModestMailOperationPrivate *priv;
494 gboolean canceled = FALSE;
496 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
501 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
503 /* Cancel the mail operation */
504 g_return_val_if_fail (priv->account, FALSE);
505 tny_account_cancel (priv->account);
507 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
508 ModestTnySendQueue *queue;
509 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
512 /* Cancel the sending of the following next messages */
513 if (TNY_IS_SEND_QUEUE (queue))
514 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
521 modest_mail_operation_get_task_done (ModestMailOperation *self)
523 ModestMailOperationPrivate *priv;
525 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
533 modest_mail_operation_get_task_total (ModestMailOperation *self)
535 ModestMailOperationPrivate *priv;
537 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 modest_mail_operation_is_finished (ModestMailOperation *self)
547 ModestMailOperationPrivate *priv;
548 gboolean retval = FALSE;
550 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
553 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
555 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
556 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
557 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
558 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
568 * Creates an image of the current state of a mail operation, the
569 * caller must free it
571 static ModestMailOperationState *
572 modest_mail_operation_clone_state (ModestMailOperation *self)
574 ModestMailOperationState *state;
575 ModestMailOperationPrivate *priv;
577 /* FIXME: this should be fixed properly
579 * in some cases, priv was NULL, so checking here to
582 g_return_val_if_fail (self, NULL);
583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
584 g_return_val_if_fail (priv, NULL);
589 state = g_slice_new (ModestMailOperationState);
591 state->status = priv->status;
592 state->op_type = priv->op_type;
593 state->done = priv->done;
594 state->total = priv->total;
595 state->finished = modest_mail_operation_is_finished (self);
596 state->bytes_done = 0;
597 state->bytes_total = 0;
602 /* ******************************************************************* */
603 /* ************************** SEND ACTIONS ************************* */
604 /* ******************************************************************* */
607 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
613 ModestMailOperationPrivate *priv;
614 ModestMailOperation *self;
616 self = MODEST_MAIL_OPERATION (user_data);
617 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
619 if (cancelled || err)
623 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
624 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
625 "Error adding a msg to the send queue\n");
626 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
628 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
631 modest_mail_operation_notify_end (self);
632 g_object_unref (self);
636 modest_mail_operation_send_mail (ModestMailOperation *self,
637 TnyTransportAccount *transport_account,
640 TnySendQueue *send_queue = NULL;
641 ModestMailOperationPrivate *priv;
643 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
644 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
645 g_return_if_fail (msg && TNY_IS_MSG (msg));
647 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
649 /* Get account and set it into mail_operation */
650 priv->account = g_object_ref (transport_account);
651 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
655 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
656 if (!TNY_IS_SEND_QUEUE(send_queue)) {
658 g_error_free (priv->error);
661 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
662 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
663 "modest: could not find send queue for account\n");
664 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
665 modest_mail_operation_notify_end (self);
667 modest_mail_operation_notify_start (self);
668 /* Add the msg to the queue. The callback will
669 finalize the mail operation */
670 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
671 NULL, g_object_ref (self));
672 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
679 idle_create_msg_cb (gpointer idle_data)
681 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
683 /* This is a GDK lock because we are an idle callback and
684 * info->callback can contain Gtk+ code */
686 gdk_threads_enter (); /* CHECKED */
687 info->callback (info->mail_op, info->msg, info->userdata);
689 g_object_unref (info->mail_op);
691 g_object_unref (info->msg);
692 g_slice_free (CreateMsgIdleInfo, info);
693 gdk_threads_leave (); /* CHECKED */
699 create_msg_thread (gpointer thread_data)
701 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
702 TnyMsg *new_msg = NULL;
703 ModestMailOperationPrivate *priv;
706 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
707 if (info->html_body == NULL) {
708 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
709 info->bcc, info->subject, info->plain_body,
710 info->attachments_list, &attached,
713 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
714 info->bcc, info->subject, info->html_body,
715 info->plain_body, info->attachments_list,
716 info->images_list, &attached,
723 /* Set priority flags in message */
724 header = tny_msg_get_header (new_msg);
725 tny_header_set_flag (header, info->priority_flags);
727 /* Set attachment flags in message */
728 if (info->attachments_list != NULL && attached > 0)
729 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
731 g_object_unref (G_OBJECT(header));
733 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
735 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
736 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
737 "modest: failed to create a new msg\n");
745 g_free (info->plain_body);
746 g_free (info->html_body);
747 g_free (info->subject);
748 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
749 g_list_free (info->attachments_list);
750 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
751 g_list_free (info->images_list);
753 if (info->callback) {
754 CreateMsgIdleInfo *idle_info;
755 idle_info = g_slice_new0 (CreateMsgIdleInfo);
756 idle_info->mail_op = g_object_ref (info->mail_op);
757 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
758 idle_info->callback = info->callback;
759 idle_info->userdata = info->userdata;
760 g_idle_add (idle_create_msg_cb, idle_info);
762 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
765 g_object_unref (info->mail_op);
766 g_slice_free (CreateMsgInfo, info);
767 if (new_msg) g_object_unref(new_msg);
773 modest_mail_operation_create_msg (ModestMailOperation *self,
774 const gchar *from, const gchar *to,
775 const gchar *cc, const gchar *bcc,
776 const gchar *subject, const gchar *plain_body,
777 const gchar *html_body,
778 const GList *attachments_list,
779 const GList *images_list,
780 TnyHeaderFlags priority_flags,
781 ModestMailOperationCreateMsgCallback callback,
784 CreateMsgInfo *info = NULL;
786 info = g_slice_new0 (CreateMsgInfo);
787 info->mail_op = g_object_ref (self);
789 info->from = g_strdup (from);
790 info->to = g_strdup (to);
791 info->cc = g_strdup (cc);
792 info->bcc = g_strdup (bcc);
793 info->subject = g_strdup (subject);
794 info->plain_body = g_strdup (plain_body);
795 info->html_body = g_strdup (html_body);
796 info->attachments_list = g_list_copy ((GList *) attachments_list);
797 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
798 info->images_list = g_list_copy ((GList *) images_list);
799 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
800 info->priority_flags = priority_flags;
802 info->callback = callback;
803 info->userdata = userdata;
805 g_thread_create (create_msg_thread, info, FALSE, NULL);
810 TnyTransportAccount *transport_account;
815 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
819 ModestMailOperationPrivate *priv = NULL;
820 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
821 TnyFolder *draft_folder = NULL;
822 TnyFolder *outbox_folder = NULL;
823 TnyHeader *header = NULL;
825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
828 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
829 modest_mail_operation_notify_end (self);
833 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
834 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
835 modest_mail_operation_notify_end (self);
839 /* Call mail operation */
840 modest_mail_operation_send_mail (self, info->transport_account, msg);
842 if (info->draft_msg != NULL) {
843 TnyList *tmp_headers = NULL;
844 TnyFolder *folder = NULL;
845 TnyFolder *src_folder = NULL;
846 TnyFolderType folder_type;
847 TnyTransportAccount *transport_account = NULL;
849 /* To remove the old mail from its source folder, we need to get the
850 * transport account of the original draft message (the transport account
851 * might have been changed by the user) */
852 header = tny_msg_get_header (info->draft_msg);
853 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
854 modest_runtime_get_account_store(), header);
855 if (transport_account == NULL)
856 transport_account = g_object_ref(info->transport_account);
857 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
858 TNY_FOLDER_TYPE_DRAFTS);
859 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
860 TNY_FOLDER_TYPE_OUTBOX);
861 g_object_unref(transport_account);
864 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
868 if (!outbox_folder) {
869 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
874 folder = tny_msg_get_folder (info->draft_msg);
875 if (folder == NULL) goto end;
876 folder_type = modest_tny_folder_guess_folder_type (folder);
878 if (folder_type == TNY_FOLDER_TYPE_INVALID)
879 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
881 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
882 src_folder = outbox_folder;
884 src_folder = draft_folder;
886 /* Note: This can fail (with a warning) if the message is not really already in a folder,
887 * because this function requires it to have a UID. */
888 tmp_headers = tny_simple_list_new ();
889 tny_list_append (tmp_headers, (GObject*) header);
890 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
891 g_object_unref (tmp_headers);
892 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
894 g_object_unref (folder);
899 g_object_unref (header);
901 g_object_unref (info->draft_msg);
903 g_object_unref (draft_folder);
905 g_object_unref (outbox_folder);
906 if (info->transport_account)
907 g_object_unref (info->transport_account);
908 g_slice_free (SendNewMailInfo, info);
912 modest_mail_operation_send_new_mail (ModestMailOperation *self,
913 TnyTransportAccount *transport_account,
915 const gchar *from, const gchar *to,
916 const gchar *cc, const gchar *bcc,
917 const gchar *subject, const gchar *plain_body,
918 const gchar *html_body,
919 const GList *attachments_list,
920 const GList *images_list,
921 TnyHeaderFlags priority_flags)
923 ModestMailOperationPrivate *priv = NULL;
924 SendNewMailInfo *info;
926 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
927 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
929 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
930 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
931 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
932 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
934 /* Check parametters */
936 /* Set status failed and set an error */
937 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
938 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
939 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
940 _("Error trying to send a mail. You need to set at least one recipient"));
943 info = g_slice_new0 (SendNewMailInfo);
944 info->transport_account = transport_account;
945 if (transport_account)
946 g_object_ref (transport_account);
947 info->draft_msg = draft_msg;
949 g_object_ref (draft_msg);
952 modest_mail_operation_notify_start (self);
953 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
954 attachments_list, images_list, priority_flags,
955 modest_mail_operation_send_new_mail_cb, info);
961 TnyTransportAccount *transport_account;
963 SaveToDraftstCallback callback;
967 ModestMailOperation *mailop;
968 } SaveToDraftsAddMsgInfo;
971 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
976 ModestMailOperationPrivate *priv = NULL;
977 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
978 GError *io_error = NULL;
980 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
982 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
983 io_error = priv->error;
987 g_warning ("%s: priv->error != NULL", __FUNCTION__);
988 g_error_free(priv->error);
991 priv->error = (err == NULL) ? NULL : g_error_copy(err);
993 if ((!priv->error) && (info->draft_msg != NULL)) {
994 TnyHeader *header = tny_msg_get_header (info->draft_msg);
995 TnyFolder *src_folder = tny_header_get_folder (header);
997 /* Remove the old draft */
998 tny_folder_remove_msg (src_folder, header, NULL);
1000 /* Synchronize to expunge and to update the msg counts */
1001 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1002 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1004 g_object_unref (G_OBJECT(header));
1005 g_object_unref (G_OBJECT(src_folder));
1009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1011 g_error_free (io_error);
1014 } else if (io_error) {
1015 priv->error = io_error;
1016 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1018 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1021 /* Call the user callback */
1023 info->callback (info->mailop, info->msg, info->user_data);
1025 if (info->transport_account)
1026 g_object_unref (G_OBJECT(info->transport_account));
1027 if (info->draft_msg)
1028 g_object_unref (G_OBJECT (info->draft_msg));
1030 g_object_unref (G_OBJECT(info->drafts));
1032 g_object_unref (G_OBJECT (info->msg));
1034 modest_mail_operation_notify_end (info->mailop);
1035 g_object_unref(info->mailop);
1036 g_slice_free (SaveToDraftsAddMsgInfo, info);
1041 TnyTransportAccount *transport_account;
1043 SaveToDraftstCallback callback;
1048 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1052 TnyFolder *drafts = NULL;
1053 ModestMailOperationPrivate *priv = NULL;
1054 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1056 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1059 if (!(priv->error)) {
1060 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1061 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1062 "modest: failed to create a new msg\n");
1065 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1066 TNY_FOLDER_TYPE_DRAFTS);
1067 if (!drafts && !(priv->error)) {
1068 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1069 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1070 "modest: failed to create a new msg\n");
1074 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1075 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1076 cb_info->transport_account = g_object_ref(info->transport_account);
1077 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1078 cb_info->callback = info->callback;
1079 cb_info->user_data = info->user_data;
1080 cb_info->drafts = g_object_ref(drafts);
1081 cb_info->msg = g_object_ref(msg);
1082 cb_info->mailop = g_object_ref(self);
1083 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1086 /* Call the user callback */
1087 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1089 info->callback (self, msg, info->user_data);
1090 modest_mail_operation_notify_end (self);
1094 g_object_unref (G_OBJECT(drafts));
1095 if (info->draft_msg)
1096 g_object_unref (G_OBJECT (info->draft_msg));
1097 if (info->transport_account)
1098 g_object_unref (G_OBJECT(info->transport_account));
1099 g_slice_free (SaveToDraftsInfo, info);
1103 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1104 TnyTransportAccount *transport_account,
1106 const gchar *from, const gchar *to,
1107 const gchar *cc, const gchar *bcc,
1108 const gchar *subject, const gchar *plain_body,
1109 const gchar *html_body,
1110 const GList *attachments_list,
1111 const GList *images_list,
1112 TnyHeaderFlags priority_flags,
1113 SaveToDraftstCallback callback,
1116 ModestMailOperationPrivate *priv = NULL;
1117 SaveToDraftsInfo *info = NULL;
1119 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1120 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1122 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1124 /* Get account and set it into mail_operation */
1125 priv->account = g_object_ref (transport_account);
1126 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1128 info = g_slice_new0 (SaveToDraftsInfo);
1129 info->transport_account = g_object_ref (transport_account);
1130 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1131 info->callback = callback;
1132 info->user_data = user_data;
1134 modest_mail_operation_notify_start (self);
1135 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1136 attachments_list, images_list, priority_flags,
1137 modest_mail_operation_save_to_drafts_cb, info);
1142 ModestMailOperation *mail_op;
1143 TnyMimePart *mime_part;
1145 GetMimePartSizeCallback callback;
1147 } GetMimePartSizeInfo;
1149 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1150 /* We use this folder observer to track the headers that have been
1151 * added to a folder */
1154 TnyList *new_headers;
1155 } InternalFolderObserver;
1158 GObjectClass parent;
1159 } InternalFolderObserverClass;
1161 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1163 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1164 internal_folder_observer,
1166 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1170 foreach_add_item (gpointer header, gpointer user_data)
1172 tny_list_prepend (TNY_LIST (user_data),
1173 g_object_ref (G_OBJECT (header)));
1176 /* This is the method that looks for new messages in a folder */
1178 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1180 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1182 TnyFolderChangeChanged changed;
1184 changed = tny_folder_change_get_changed (change);
1186 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1189 /* Get added headers */
1190 list = tny_simple_list_new ();
1191 tny_folder_change_get_added_headers (change, list);
1193 /* Add them to the folder observer */
1194 tny_list_foreach (list, foreach_add_item,
1195 derived->new_headers);
1197 g_object_unref (G_OBJECT (list));
1202 internal_folder_observer_init (InternalFolderObserver *self)
1204 self->new_headers = tny_simple_list_new ();
1207 internal_folder_observer_finalize (GObject *object)
1209 InternalFolderObserver *self;
1211 self = (InternalFolderObserver *) object;
1212 g_object_unref (self->new_headers);
1214 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1217 tny_folder_observer_init (TnyFolderObserverIface *iface)
1219 iface->update = internal_folder_observer_update;
1222 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1224 GObjectClass *object_class;
1226 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1227 object_class = (GObjectClass*) klass;
1228 object_class->finalize = internal_folder_observer_finalize;
1233 ModestMailOperation *mail_op;
1234 gchar *account_name;
1235 UpdateAccountCallback callback;
1240 TnyFolderObserver *inbox_observer;
1241 RetrieveAllCallback retrieve_all_cb;
1242 gboolean interactive;
1243 } UpdateAccountInfo;
1247 destroy_update_account_info (UpdateAccountInfo *info)
1249 g_free (info->account_name);
1250 g_object_unref (info->folders);
1251 g_object_unref (info->mail_op);
1252 g_slice_free (UpdateAccountInfo, info);
1256 update_account_get_msg_async_cb (TnyFolder *folder,
1262 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1264 /* Just delete the helper. Don't do anything with the new
1265 msg. There is also no need to check for errors */
1266 g_object_unref (msg_info->mail_op);
1267 g_object_unref (msg_info->header);
1268 g_slice_free (GetMsgInfo, msg_info);
1272 update_account_notify_user_and_free (UpdateAccountInfo *info,
1273 TnyList *new_headers)
1275 /* Set the account back to not busy */
1276 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1277 info->account_name, FALSE);
1281 info->callback (info->mail_op, new_headers, info->user_data);
1283 /* Mail operation end */
1284 modest_mail_operation_notify_end (info->mail_op);
1288 g_object_unref (new_headers);
1289 destroy_update_account_info (info);
1293 inbox_refreshed_cb (TnyFolder *inbox,
1298 UpdateAccountInfo *info;
1299 ModestMailOperationPrivate *priv;
1300 TnyIterator *new_headers_iter;
1301 GPtrArray *new_headers_array = NULL;
1302 gint max_size, retrieve_limit, i;
1303 ModestAccountMgr *mgr;
1304 ModestAccountRetrieveType retrieve_type;
1305 TnyList *new_headers = NULL;
1306 gboolean headers_only, ignore_limit;
1307 TnyTransportAccount *transport_account = NULL;
1309 info = (UpdateAccountInfo *) user_data;
1310 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1311 mgr = modest_runtime_get_account_mgr ();
1313 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1314 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1316 if (canceled || err) {
1317 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1319 priv->error = g_error_copy (err);
1321 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1322 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1325 /* Notify the user about the error and then exit */
1326 update_account_notify_user_and_free (info, NULL);
1331 /* Try to send anyway */
1335 /* Get the message max size */
1336 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1337 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1339 max_size = G_MAXINT;
1341 max_size = max_size * KB;
1343 /* Create the new headers array. We need it to sort the
1344 new headers by date */
1345 new_headers_array = g_ptr_array_new ();
1346 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1347 while (!tny_iterator_is_done (new_headers_iter)) {
1348 TnyHeader *header = NULL;
1350 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1351 /* Apply per-message size limits */
1352 if (tny_header_get_message_size (header) < max_size)
1353 g_ptr_array_add (new_headers_array, g_object_ref (header));
1355 g_object_unref (header);
1356 tny_iterator_next (new_headers_iter);
1358 g_object_unref (new_headers_iter);
1359 tny_folder_remove_observer (inbox, info->inbox_observer);
1360 g_object_unref (info->inbox_observer);
1361 info->inbox_observer = NULL;
1363 if (new_headers_array->len == 0)
1366 /* Get per-account message amount retrieval limit */
1367 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1368 if (retrieve_limit == 0)
1369 retrieve_limit = G_MAXINT;
1371 /* Get per-account retrieval type */
1372 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1373 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1376 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1378 /* Ask the users if they want to retrieve all the messages
1379 even though the limit was exceeded */
1380 ignore_limit = FALSE;
1381 if (new_headers_array->len > retrieve_limit) {
1382 /* Ask the user if a callback has been specified and
1383 if the mail operation has a source (this means that
1384 was invoked by the user and not automatically by a
1386 if (info->retrieve_all_cb && priv->source)
1387 ignore_limit = info->retrieve_all_cb (priv->source,
1388 new_headers_array->len,
1392 if (!headers_only) {
1394 const gint msg_list_size = compute_message_array_size (new_headers_array);
1398 priv->total = new_headers_array->len;
1400 priv->total = MIN (new_headers_array->len, retrieve_limit);
1401 while (msg_num < priv->total) {
1402 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1403 TnyFolder *folder = tny_header_get_folder (header);
1404 GetMsgInfo *msg_info;
1406 /* Create the message info */
1407 msg_info = g_slice_new0 (GetMsgInfo);
1408 msg_info->mail_op = g_object_ref (info->mail_op);
1409 msg_info->header = g_object_ref (header);
1410 msg_info->total_bytes = msg_list_size;
1412 /* Get message in an async way */
1413 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1414 get_msg_status_cb, msg_info);
1416 g_object_unref (folder);
1422 /* Copy the headers to a list and free the array */
1423 new_headers = tny_simple_list_new ();
1424 for (i=0; i < new_headers_array->len; i++) {
1425 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1426 tny_list_append (new_headers, G_OBJECT (header));
1428 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1429 g_ptr_array_free (new_headers_array, FALSE);
1432 /* Get the transport account */
1433 transport_account = (TnyTransportAccount *)
1434 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1435 info->account_name);
1437 if (transport_account) {
1438 ModestTnySendQueue *send_queue;
1442 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1443 g_object_unref (transport_account);
1445 if (TNY_IS_SEND_QUEUE (send_queue)) {
1446 /* Get outbox folder */
1447 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1448 if (outbox) { /* this could fail in some cases */
1449 num_messages = tny_folder_get_all_count (outbox);
1450 g_object_unref (outbox);
1452 g_warning ("%s: could not get outbox", __FUNCTION__);
1456 if (num_messages != 0) {
1457 /* Reenable suspended items */
1458 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1461 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1462 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1468 /* Check if the operation was a success */
1470 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1472 /* Call the user callback and free */
1473 update_account_notify_user_and_free (info, new_headers);
1477 inbox_refresh_status_update (GObject *obj,
1481 UpdateAccountInfo *info = NULL;
1482 ModestMailOperation *self = NULL;
1483 ModestMailOperationPrivate *priv = NULL;
1484 ModestMailOperationState *state;
1486 g_return_if_fail (user_data != NULL);
1487 g_return_if_fail (status != NULL);
1489 /* Show only the status information we want */
1490 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1493 info = (UpdateAccountInfo *) user_data;
1494 self = info->mail_op;
1495 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1499 priv->done = status->position;
1500 priv->total = status->of_total;
1502 state = modest_mail_operation_clone_state (self);
1504 /* This is not a GDK lock because we are a Tinymail callback and
1505 * Tinymail already acquires the Gdk lock */
1506 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1508 g_slice_free (ModestMailOperationState, state);
1512 recurse_folders_async_cb (TnyFolderStore *folder_store,
1518 UpdateAccountInfo *info;
1519 ModestMailOperationPrivate *priv;
1521 info = (UpdateAccountInfo *) user_data;
1522 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1524 if (err || canceled) {
1525 /* If the error was previosly set by another callback
1526 don't set it again */
1528 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1530 priv->error = g_error_copy (err);
1532 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1533 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1537 /* We're not getting INBOX children if we don't want to poke all */
1538 TnyIterator *iter = tny_list_create_iterator (list);
1539 while (!tny_iterator_is_done (iter)) {
1540 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1542 /* Add to the list of all folders */
1543 tny_list_append (info->folders, (GObject *) folder);
1545 if (info->poke_all) {
1546 TnyList *folders = tny_simple_list_new ();
1547 /* Add pending call */
1548 info->pending_calls++;
1550 tny_folder_store_get_folders_async (folder, folders, NULL,
1551 recurse_folders_async_cb,
1553 g_object_unref (folders);
1556 g_object_unref (G_OBJECT (folder));
1558 tny_iterator_next (iter);
1560 g_object_unref (G_OBJECT (iter));
1563 /* Remove my own pending call */
1564 info->pending_calls--;
1566 /* This means that we have all the folders */
1567 if (info->pending_calls == 0) {
1568 TnyIterator *iter_all_folders;
1569 TnyFolder *inbox = NULL;
1571 /* If there was any error do not continue */
1573 update_account_notify_user_and_free (info, NULL);
1577 iter_all_folders = tny_list_create_iterator (info->folders);
1579 /* Do a poke status over all folders */
1580 while (!tny_iterator_is_done (iter_all_folders) &&
1581 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1582 TnyFolder *folder = NULL;
1584 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1586 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1587 /* Get a reference to the INBOX */
1588 inbox = g_object_ref (folder);
1590 /* Issue a poke status over the folder */
1592 tny_folder_poke_status (folder);
1595 /* Free and go to next */
1596 g_object_unref (folder);
1597 tny_iterator_next (iter_all_folders);
1599 g_object_unref (iter_all_folders);
1601 /* Refresh the INBOX */
1603 /* Refresh the folder. Our observer receives
1604 * the new emails during folder refreshes, so
1605 * we can use observer->new_headers
1607 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1608 tny_folder_add_observer (inbox, info->inbox_observer);
1610 /* Refresh the INBOX */
1611 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1612 g_object_unref (inbox);
1614 /* We could not perform the inbox refresh but
1615 we'll try to send mails anyway */
1616 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1622 modest_mail_operation_update_account (ModestMailOperation *self,
1623 const gchar *account_name,
1625 gboolean interactive,
1626 RetrieveAllCallback retrieve_all_cb,
1627 UpdateAccountCallback callback,
1630 UpdateAccountInfo *info = NULL;
1631 ModestMailOperationPrivate *priv = NULL;
1632 ModestTnyAccountStore *account_store = NULL;
1634 ModestMailOperationState *state;
1636 /* Init mail operation */
1637 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1641 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1643 /* Get the store account */
1644 account_store = modest_runtime_get_account_store ();
1646 modest_tny_account_store_get_server_account (account_store,
1648 TNY_ACCOUNT_TYPE_STORE);
1650 /* The above function could return NULL */
1651 if (!priv->account) {
1652 /* Check if the operation was a success */
1653 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1654 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1656 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1658 /* Call the user callback */
1660 callback (self, NULL, user_data);
1662 /* Notify about operation end */
1663 modest_mail_operation_notify_end (self);
1668 /* We have once seen priv->account getting finalized during this code,
1669 * therefore adding a reference (bug #82296) */
1671 g_object_ref (priv->account);
1673 /* Create the helper object */
1674 info = g_slice_new0 (UpdateAccountInfo);
1675 info->pending_calls = 1;
1676 info->folders = tny_simple_list_new ();
1677 info->mail_op = g_object_ref (self);
1678 info->poke_all = poke_all;
1679 info->interactive = interactive;
1680 info->account_name = g_strdup (account_name);
1681 info->callback = callback;
1682 info->user_data = user_data;
1683 info->retrieve_all_cb = retrieve_all_cb;
1685 /* Set account busy */
1686 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1687 modest_mail_operation_notify_start (self);
1689 /* notify about the start of the operation */
1690 state = modest_mail_operation_clone_state (self);
1694 /* Start notifying progress */
1695 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1696 g_slice_free (ModestMailOperationState, state);
1698 /* Get all folders and continue in the callback */
1699 folders = tny_simple_list_new ();
1700 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1702 recurse_folders_async_cb,
1704 g_object_unref (folders);
1706 g_object_unref (priv->account);
1711 * Used to notify the queue from the main
1712 * loop. We call it inside an idle call to achieve that
1715 idle_notify_queue (gpointer data)
1717 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1719 gdk_threads_enter ();
1720 modest_mail_operation_notify_end (mail_op);
1721 gdk_threads_leave ();
1722 g_object_unref (mail_op);
1728 compare_headers_by_date (gconstpointer a,
1731 TnyHeader **header1, **header2;
1732 time_t sent1, sent2;
1734 header1 = (TnyHeader **) a;
1735 header2 = (TnyHeader **) b;
1737 sent1 = tny_header_get_date_sent (*header1);
1738 sent2 = tny_header_get_date_sent (*header2);
1740 /* We want the most recent ones (greater time_t) at the
1749 /* ******************************************************************* */
1750 /* ************************** STORE ACTIONS ************************* */
1751 /* ******************************************************************* */
1754 ModestMailOperation *mail_op;
1755 CreateFolderUserCallback callback;
1761 create_folder_cb (TnyFolderStore *parent_folder,
1763 TnyFolder *new_folder,
1767 ModestMailOperationPrivate *priv;
1768 CreateFolderInfo *info;
1770 info = (CreateFolderInfo *) user_data;
1771 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1773 if (canceled || err) {
1774 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1776 priv->error = g_error_copy (err);
1778 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1779 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1782 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1785 /* The user will unref the new_folder */
1787 info->callback (info->mail_op, parent_folder,
1788 new_folder, info->user_data);
1790 /* Notify about operation end */
1791 modest_mail_operation_notify_end (info->mail_op);
1794 g_object_unref (info->mail_op);
1795 g_slice_free (CreateFolderInfo, info);
1799 modest_mail_operation_create_folder (ModestMailOperation *self,
1800 TnyFolderStore *parent,
1802 CreateFolderUserCallback callback,
1805 ModestMailOperationPrivate *priv;
1807 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1808 g_return_if_fail (name);
1810 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1811 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1812 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1813 g_object_ref (parent) :
1814 modest_tny_folder_get_account (TNY_FOLDER (parent));
1816 /* Check for already existing folder */
1817 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1818 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1819 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1820 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1821 _CS("ckdg_ib_folder_already_exists"));
1825 if (TNY_IS_FOLDER (parent)) {
1826 /* Check folder rules */
1827 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1828 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1829 /* Set status failed and set an error */
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1831 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1832 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1833 _("mail_in_ui_folder_create_error"));
1837 if (!strcmp (name, " ") || strchr (name, '/')) {
1838 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1839 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1840 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1841 _("mail_in_ui_folder_create_error"));
1845 CreateFolderInfo *info;
1847 info = g_slice_new0 (CreateFolderInfo);
1848 info->mail_op = g_object_ref (self);
1849 info->callback = callback;
1850 info->user_data = user_data;
1852 modest_mail_operation_notify_start (self);
1854 /* Create the folder */
1855 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1858 /* Call the user callback anyway */
1860 callback (self, parent, NULL, user_data);
1861 /* Notify about operation end */
1862 modest_mail_operation_notify_end (self);
1867 modest_mail_operation_remove_folder (ModestMailOperation *self,
1869 gboolean remove_to_trash)
1871 ModestMailOperationPrivate *priv;
1872 ModestTnyFolderRules rules;
1874 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1875 g_return_if_fail (TNY_IS_FOLDER (folder));
1877 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1879 /* Check folder rules */
1880 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1881 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1882 /* Set status failed and set an error */
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1884 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1885 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1886 _("mail_in_ui_folder_delete_error"));
1890 /* Get the account */
1891 priv->account = modest_tny_folder_get_account (folder);
1892 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1894 /* Delete folder or move to trash */
1895 if (remove_to_trash) {
1896 TnyFolder *trash_folder = NULL;
1897 trash_folder = modest_tny_account_get_special_folder (priv->account,
1898 TNY_FOLDER_TYPE_TRASH);
1899 /* TODO: error_handling */
1901 modest_mail_operation_notify_start (self);
1902 modest_mail_operation_xfer_folder (self, folder,
1903 TNY_FOLDER_STORE (trash_folder),
1905 g_object_unref (trash_folder);
1907 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1910 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1912 modest_mail_operation_notify_start (self);
1913 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1914 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1917 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1919 g_object_unref (parent);
1921 g_warning ("%s: could not get parent folder", __FUNCTION__);
1925 /* Notify about operation end */
1926 modest_mail_operation_notify_end (self);
1930 transfer_folder_status_cb (GObject *obj,
1934 ModestMailOperation *self;
1935 ModestMailOperationPrivate *priv;
1936 ModestMailOperationState *state;
1937 XFerFolderAsyncHelper *helper;
1939 g_return_if_fail (status != NULL);
1941 /* Show only the status information we want */
1942 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1945 helper = (XFerFolderAsyncHelper *) user_data;
1946 g_return_if_fail (helper != NULL);
1948 self = helper->mail_op;
1949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1951 priv->done = status->position;
1952 priv->total = status->of_total;
1954 state = modest_mail_operation_clone_state (self);
1956 /* This is not a GDK lock because we are a Tinymail callback
1957 * which is already GDK locked by Tinymail */
1959 /* no gdk_threads_enter (), CHECKED */
1961 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1963 /* no gdk_threads_leave (), CHECKED */
1965 g_slice_free (ModestMailOperationState, state);
1970 transfer_folder_cb (TnyFolder *folder,
1972 TnyFolderStore *into,
1973 TnyFolder *new_folder,
1977 XFerFolderAsyncHelper *helper;
1978 ModestMailOperation *self = NULL;
1979 ModestMailOperationPrivate *priv = NULL;
1981 helper = (XFerFolderAsyncHelper *) user_data;
1982 g_return_if_fail (helper != NULL);
1984 self = helper->mail_op;
1985 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1988 priv->error = g_error_copy (err);
1990 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1991 } else if (cancelled) {
1992 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1993 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1994 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1995 _("Transference of %s was cancelled."),
1996 tny_folder_get_name (folder));
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2002 /* Notify about operation end */
2003 modest_mail_operation_notify_end (self);
2005 /* If user defined callback function was defined, call it */
2006 if (helper->user_callback) {
2008 /* This is not a GDK lock because we are a Tinymail callback
2009 * which is already GDK locked by Tinymail */
2011 /* no gdk_threads_enter (), CHECKED */
2012 helper->user_callback (self, new_folder, helper->user_data);
2013 /* no gdk_threads_leave () , CHECKED */
2017 g_object_unref (helper->mail_op);
2018 g_slice_free (XFerFolderAsyncHelper, helper);
2023 * This function checks if the new name is a valid name for our local
2024 * folders account. The new name could not be the same than then name
2025 * of any of the mandatory local folders
2027 * We can not rely on tinymail because tinymail does not check the
2028 * name of the virtual folders that the account could have in the case
2029 * that we're doing a rename (because it directly calls Camel which
2030 * knows nothing about our virtual folders).
2032 * In the case of an actual copy/move (i.e. move/copy a folder between
2033 * accounts) tinymail uses the tny_folder_store_create_account which
2034 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2035 * checks the new name of the folder, so this call in that case
2036 * wouldn't be needed. *But* NOTE that if tinymail changes its
2037 * implementation (if folder transfers within the same account is no
2038 * longer implemented as a rename) this call will allow Modest to work
2041 * If the new name is not valid, this function will set the status to
2042 * failed and will set also an error in the mail operation
2045 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2046 TnyFolderStore *into,
2047 const gchar *new_name)
2049 if (TNY_IS_ACCOUNT (into) &&
2050 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2051 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2056 _CS("ckdg_ib_folder_already_exists"));
2063 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2065 TnyFolderStore *parent,
2066 gboolean delete_original,
2067 XferFolderAsyncUserCallback user_callback,
2070 ModestMailOperationPrivate *priv = NULL;
2071 ModestTnyFolderRules parent_rules = 0, rules;
2072 XFerFolderAsyncHelper *helper = NULL;
2073 const gchar *folder_name = NULL;
2074 const gchar *error_msg;
2076 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2077 g_return_if_fail (TNY_IS_FOLDER (folder));
2078 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2081 folder_name = tny_folder_get_name (folder);
2083 /* Set the error msg */
2084 error_msg = _("mail_in_ui_folder_move_target_error");
2086 /* Get account and set it into mail_operation */
2087 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2088 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2089 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2091 /* Get folder rules */
2092 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2093 if (TNY_IS_FOLDER (parent))
2094 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2096 /* Apply operation constraints */
2097 if ((gpointer) parent == (gpointer) folder ||
2098 (!TNY_IS_FOLDER_STORE (parent)) ||
2099 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2102 } else if (TNY_IS_FOLDER (parent) &&
2103 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2107 } else if (TNY_IS_FOLDER (parent) &&
2108 TNY_IS_FOLDER_STORE (folder) &&
2109 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2110 TNY_FOLDER_STORE (folder))) {
2111 /* Do not move a parent into a child */
2113 } else if (TNY_IS_FOLDER_STORE (parent) &&
2114 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2115 /* Check that the new folder name is not used by any
2118 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2119 /* Check that the new folder name is not used by any
2120 special local folder */
2123 /* Create the helper */
2124 helper = g_slice_new0 (XFerFolderAsyncHelper);
2125 helper->mail_op = g_object_ref (self);
2126 helper->user_callback = user_callback;
2127 helper->user_data = user_data;
2129 /* Move/Copy folder */
2130 modest_mail_operation_notify_start (self);
2131 tny_folder_copy_async (folder,
2133 tny_folder_get_name (folder),
2136 transfer_folder_status_cb,
2142 /* Set status failed and set an error */
2143 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2144 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2145 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2148 /* Call the user callback if exists */
2150 user_callback (self, NULL, user_data);
2152 /* Notify the queue */
2153 modest_mail_operation_notify_end (self);
2157 modest_mail_operation_rename_folder (ModestMailOperation *self,
2160 XferFolderAsyncUserCallback user_callback,
2163 ModestMailOperationPrivate *priv;
2164 ModestTnyFolderRules rules;
2165 XFerFolderAsyncHelper *helper;
2167 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2168 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2169 g_return_if_fail (name);
2171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2173 /* Get account and set it into mail_operation */
2174 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2175 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2177 /* Check folder rules */
2178 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2179 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2181 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2184 TnyFolderStore *into;
2186 into = tny_folder_get_folder_store (folder);
2188 /* Check that the new folder name is not used by any
2189 special local folder */
2190 if (new_name_valid_if_local_account (priv, into, name)) {
2191 /* Create the helper */
2192 helper = g_slice_new0 (XFerFolderAsyncHelper);
2193 helper->mail_op = g_object_ref(self);
2194 helper->user_callback = user_callback;
2195 helper->user_data = user_data;
2197 /* Rename. Camel handles folder subscription/unsubscription */
2198 modest_mail_operation_notify_start (self);
2199 tny_folder_copy_async (folder, into, name, TRUE,
2201 transfer_folder_status_cb,
2203 g_object_unref (into);
2205 g_object_unref (into);
2212 /* Set status failed and set an error */
2213 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2214 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2215 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2216 _("FIXME: unable to rename"));
2219 user_callback (self, NULL, user_data);
2221 /* Notify about operation end */
2222 modest_mail_operation_notify_end (self);
2225 /* ******************************************************************* */
2226 /* ************************** MSG ACTIONS ************************* */
2227 /* ******************************************************************* */
2230 modest_mail_operation_get_msg (ModestMailOperation *self,
2232 gboolean progress_feedback,
2233 GetMsgAsyncUserCallback user_callback,
2236 GetMsgInfo *helper = NULL;
2238 ModestMailOperationPrivate *priv;
2240 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2241 g_return_if_fail (TNY_IS_HEADER (header));
2243 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2248 /* Check memory low */
2249 if (_check_memory_low (self)) {
2251 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2252 modest_mail_operation_notify_end (self);
2256 /* Get account and set it into mail_operation */
2257 folder = tny_header_get_folder (header);
2258 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2260 /* Check for cached messages */
2261 if (progress_feedback) {
2262 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2263 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2265 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2267 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2270 /* Create the helper */
2271 helper = g_slice_new0 (GetMsgInfo);
2272 helper->header = g_object_ref (header);
2273 helper->mail_op = g_object_ref (self);
2274 helper->user_callback = user_callback;
2275 helper->user_data = user_data;
2276 helper->destroy_notify = NULL;
2277 helper->last_total_bytes = 0;
2278 helper->sum_total_bytes = 0;
2279 helper->total_bytes = tny_header_get_message_size (header);
2280 helper->more_msgs = NULL;
2282 modest_mail_operation_notify_start (self);
2284 /* notify about the start of the operation */
2285 ModestMailOperationState *state;
2286 state = modest_mail_operation_clone_state (self);
2289 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2291 g_slice_free (ModestMailOperationState, state);
2293 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2295 g_object_unref (G_OBJECT (folder));
2299 get_msg_status_cb (GObject *obj,
2303 GetMsgInfo *helper = NULL;
2305 g_return_if_fail (status != NULL);
2307 /* Show only the status information we want */
2308 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2311 helper = (GetMsgInfo *) user_data;
2312 g_return_if_fail (helper != NULL);
2314 /* Notify progress */
2315 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2316 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2320 get_msg_async_cb (TnyFolder *folder,
2326 GetMsgInfo *info = NULL;
2327 ModestMailOperationPrivate *priv = NULL;
2330 info = (GetMsgInfo *) user_data;
2332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2335 if (info->more_msgs) {
2336 tny_iterator_next (info->more_msgs);
2337 finished = (tny_iterator_is_done (info->more_msgs));
2339 finished = (priv->done == priv->total) ? TRUE : FALSE;
2342 /* If canceled by the user, ignore the error given by Tinymail */
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2348 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2350 priv->error = g_error_copy ((const GError *) err);
2351 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2354 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2355 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2358 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2359 /* Set the success status before calling the user callback */
2360 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2364 /* Call the user callback */
2365 if (info->user_callback)
2366 info->user_callback (info->mail_op, info->header, canceled,
2367 msg, err, info->user_data);
2369 /* Notify about operation end if this is the last callback */
2371 /* Free user data */
2372 if (info->destroy_notify)
2373 info->destroy_notify (info->user_data);
2375 /* Notify about operation end */
2376 modest_mail_operation_notify_end (info->mail_op);
2379 if (info->more_msgs)
2380 g_object_unref (info->more_msgs);
2381 g_object_unref (info->header);
2382 g_object_unref (info->mail_op);
2383 g_slice_free (GetMsgInfo, info);
2384 } else if (info->more_msgs) {
2385 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2386 TnyFolder *folder = tny_header_get_folder (header);
2388 g_object_unref (info->header);
2389 info->header = g_object_ref (header);
2391 /* Retrieve the next message */
2392 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2394 g_object_unref (header);
2395 g_object_unref (folder);
2397 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2402 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2403 TnyList *header_list,
2404 GetMsgAsyncUserCallback user_callback,
2406 GDestroyNotify notify)
2408 ModestMailOperationPrivate *priv = NULL;
2410 TnyIterator *iter = NULL;
2411 gboolean has_uncached_messages;
2413 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2415 /* Init mail operation */
2416 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2417 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2419 priv->total = tny_list_get_length(header_list);
2421 /* Check memory low */
2422 if (_check_memory_low (self)) {
2423 if (user_callback) {
2424 TnyHeader *header = NULL;
2427 if (tny_list_get_length (header_list) > 0) {
2428 iter = tny_list_create_iterator (header_list);
2429 header = (TnyHeader *) tny_iterator_get_current (iter);
2430 g_object_unref (iter);
2432 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2434 g_object_unref (header);
2438 /* Notify about operation end */
2439 modest_mail_operation_notify_end (self);
2443 /* Check uncached messages */
2444 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2445 !has_uncached_messages && !tny_iterator_is_done (iter);
2446 tny_iterator_next (iter)) {
2449 header = (TnyHeader *) tny_iterator_get_current (iter);
2450 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2451 has_uncached_messages = TRUE;
2452 g_object_unref (header);
2454 g_object_unref (iter);
2455 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2457 /* Get account and set it into mail_operation */
2458 if (tny_list_get_length (header_list) >= 1) {
2459 TnyIterator *iterator = tny_list_create_iterator (header_list);
2460 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2462 TnyFolder *folder = tny_header_get_folder (header);
2464 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2465 g_object_unref (folder);
2467 g_object_unref (header);
2469 g_object_unref (iterator);
2472 msg_list_size = compute_message_list_size (header_list);
2474 modest_mail_operation_notify_start (self);
2475 iter = tny_list_create_iterator (header_list);
2476 if (!tny_iterator_is_done (iter)) {
2477 /* notify about the start of the operation */
2478 ModestMailOperationState *state;
2479 state = modest_mail_operation_clone_state (self);
2482 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2485 GetMsgInfo *msg_info = NULL;
2486 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2487 TnyFolder *folder = tny_header_get_folder (header);
2489 /* Create the message info */
2490 msg_info = g_slice_new0 (GetMsgInfo);
2491 msg_info->mail_op = g_object_ref (self);
2492 msg_info->header = g_object_ref (header);
2493 msg_info->more_msgs = g_object_ref (iter);
2494 msg_info->user_callback = user_callback;
2495 msg_info->user_data = user_data;
2496 msg_info->destroy_notify = notify;
2497 msg_info->last_total_bytes = 0;
2498 msg_info->sum_total_bytes = 0;
2499 msg_info->total_bytes = msg_list_size;
2501 /* The callback will call it per each header */
2502 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2504 /* Free and go on */
2505 g_object_unref (header);
2506 g_object_unref (folder);
2507 g_slice_free (ModestMailOperationState, state);
2509 g_object_unref (iter);
2514 remove_msgs_async_cb (TnyFolder *folder,
2519 gboolean expunge, leave_on_server;
2520 const gchar *account_name;
2522 TnyAccount *account;
2523 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2524 ModestMailOperation *self;
2525 ModestMailOperationPrivate *priv;
2527 self = (ModestMailOperation *) user_data;
2528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2530 if (canceled || err) {
2531 /* If canceled by the user, ignore the error given by Tinymail */
2533 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2535 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2536 priv->error = g_error_copy ((const GError *) err);
2537 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2540 modest_mail_operation_notify_end (self);
2541 g_object_unref (self);
2545 account = tny_folder_get_account (folder);
2546 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2548 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2550 proto = tny_account_get_proto (account);
2551 g_object_unref (account);
2554 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2556 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2557 modest_tny_folder_is_remote_folder (folder) == FALSE)
2563 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2568 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2570 gboolean remove_to_trash /*ignored*/)
2572 TnyFolder *folder = NULL;
2573 ModestMailOperationPrivate *priv;
2574 TnyIterator *iter = NULL;
2575 TnyHeader *header = NULL;
2576 TnyList *remove_headers = NULL;
2577 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2579 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2580 g_return_if_fail (TNY_IS_LIST (headers));
2582 if (remove_to_trash)
2583 g_warning ("remove to trash is not implemented");
2585 if (tny_list_get_length(headers) == 0) {
2586 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2587 goto cleanup; /* nothing to do */
2590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2591 remove_headers = g_object_ref(headers);
2593 /* Get folder from first header and sync it */
2594 iter = tny_list_create_iterator (headers);
2595 header = TNY_HEADER (tny_iterator_get_current (iter));
2597 folder = tny_header_get_folder (header);
2598 if (!TNY_IS_FOLDER(folder)) {
2599 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2603 /* Don't remove messages that are being sent */
2604 if (modest_tny_folder_is_local_folder (folder)) {
2605 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2607 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2608 TnyTransportAccount *traccount = NULL;
2609 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2610 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2612 ModestTnySendQueueStatus status;
2613 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2615 if (TNY_IS_SEND_QUEUE (send_queue)) {
2616 TnyIterator *iter = tny_list_create_iterator(headers);
2617 g_object_unref(remove_headers);
2618 remove_headers = TNY_LIST(tny_simple_list_new());
2619 while (!tny_iterator_is_done(iter)) {
2621 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2622 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2623 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2624 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2625 tny_list_append(remove_headers, G_OBJECT(hdr));
2627 g_object_unref(hdr);
2629 tny_iterator_next(iter);
2631 g_object_unref(iter);
2633 g_object_unref(traccount);
2637 /* Get account and set it into mail_operation */
2638 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2639 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2640 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2642 /* remove message from folder */
2643 modest_mail_operation_notify_start (self);
2644 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2645 NULL, g_object_ref (self));
2649 g_object_unref (remove_headers);
2651 g_object_unref (header);
2653 g_object_unref (iter);
2655 g_object_unref (folder);
2659 notify_progress_of_multiple_messages (ModestMailOperation *self,
2661 gint *last_total_bytes,
2662 gint *sum_total_bytes,
2664 gboolean increment_done)
2666 ModestMailOperationPrivate *priv;
2667 ModestMailOperationState *state;
2668 gboolean is_num_bytes = FALSE;
2670 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2672 /* We know that tinymail sends us information about
2673 * transferred bytes with this particular message
2675 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2676 * I just added the 'if' so we don't get runtime warning)
2678 if (status->message)
2679 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2681 state = modest_mail_operation_clone_state (self);
2682 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2683 /* We know that we're in a different message when the
2684 total number of bytes to transfer is different. Of
2685 course it could fail if we're transferring messages
2686 of the same size, but this is a workarround */
2687 if (status->of_total != *last_total_bytes) {
2688 /* We need to increment the done when there is
2689 no information about each individual
2690 message, we need to do this in message
2691 transfers, and we don't do it for getting
2695 *sum_total_bytes += *last_total_bytes;
2696 *last_total_bytes = status->of_total;
2698 state->bytes_done += status->position + *sum_total_bytes;
2699 state->bytes_total = total_bytes;
2701 /* Notify the status change. Only notify about changes
2702 referred to bytes */
2703 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2707 g_slice_free (ModestMailOperationState, state);
2711 transfer_msgs_status_cb (GObject *obj,
2715 XFerMsgsAsyncHelper *helper;
2717 g_return_if_fail (status != NULL);
2719 /* Show only the status information we want */
2720 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2723 helper = (XFerMsgsAsyncHelper *) user_data;
2724 g_return_if_fail (helper != NULL);
2726 /* Notify progress */
2727 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2728 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2732 transfer_msgs_sync_folder_cb (TnyFolder *self,
2737 XFerMsgsAsyncHelper *helper;
2738 /* We don't care here about the results of the
2740 helper = (XFerMsgsAsyncHelper *) user_data;
2742 /* Notify about operation end */
2743 modest_mail_operation_notify_end (helper->mail_op);
2745 /* If user defined callback function was defined, call it */
2746 if (helper->user_callback)
2747 helper->user_callback (helper->mail_op, helper->user_data);
2750 if (helper->more_msgs)
2751 g_object_unref (helper->more_msgs);
2752 if (helper->headers)
2753 g_object_unref (helper->headers);
2754 if (helper->dest_folder)
2755 g_object_unref (helper->dest_folder);
2756 if (helper->mail_op)
2757 g_object_unref (helper->mail_op);
2758 g_slice_free (XFerMsgsAsyncHelper, helper);
2762 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2764 XFerMsgsAsyncHelper *helper;
2765 ModestMailOperation *self;
2766 ModestMailOperationPrivate *priv;
2767 gboolean finished = TRUE;
2769 helper = (XFerMsgsAsyncHelper *) user_data;
2770 self = helper->mail_op;
2772 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2775 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2777 priv->error = g_error_copy (err);
2779 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2780 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2781 if (helper->more_msgs) {
2782 /* We'll transfer the next message in the list */
2783 tny_iterator_next (helper->more_msgs);
2784 if (!tny_iterator_is_done (helper->more_msgs)) {
2785 GObject *next_header;
2786 g_object_unref (helper->headers);
2787 helper->headers = tny_simple_list_new ();
2788 next_header = tny_iterator_get_current (helper->more_msgs);
2789 tny_list_append (helper->headers, next_header);
2790 g_object_unref (next_header);
2796 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2801 /* Synchronize the source folder contents. This should
2802 be done by tinymail but the camel_folder_sync it's
2803 actually disabled in transfer_msgs_thread_clean
2804 because it's supposed to cause hangs */
2805 tny_folder_sync_async (folder, helper->delete,
2806 transfer_msgs_sync_folder_cb,
2809 /* Transfer more messages */
2810 tny_folder_transfer_msgs_async (folder,
2812 helper->dest_folder,
2815 transfer_msgs_status_cb,
2821 compute_message_list_size (TnyList *headers)
2826 iter = tny_list_create_iterator (headers);
2827 while (!tny_iterator_is_done (iter)) {
2828 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2829 size += tny_header_get_message_size (header);
2830 g_object_unref (header);
2831 tny_iterator_next (iter);
2833 g_object_unref (iter);
2839 compute_message_array_size (GPtrArray *headers)
2844 for (i = 0; i < headers->len; i++) {
2845 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2846 size += tny_header_get_message_size (header);
2854 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2857 gboolean delete_original,
2858 XferMsgsAsyncUserCallback user_callback,
2861 ModestMailOperationPrivate *priv = NULL;
2862 TnyIterator *iter = NULL;
2863 TnyFolder *src_folder = NULL;
2864 XFerMsgsAsyncHelper *helper = NULL;
2865 TnyHeader *header = NULL;
2866 ModestTnyFolderRules rules = 0;
2867 TnyAccount *dst_account = NULL;
2868 gboolean leave_on_server;
2869 ModestMailOperationState *state;
2871 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2872 g_return_if_fail (headers && TNY_IS_LIST (headers));
2873 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2876 priv->total = tny_list_get_length (headers);
2878 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2879 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2881 /* Apply folder rules */
2882 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2883 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2884 /* Set status failed and set an error */
2885 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2886 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2887 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2888 _CS("ckct_ib_unable_to_paste_here"));
2889 /* Notify the queue */
2890 modest_mail_operation_notify_end (self);
2894 /* Get source folder */
2895 iter = tny_list_create_iterator (headers);
2896 header = TNY_HEADER (tny_iterator_get_current (iter));
2898 src_folder = tny_header_get_folder (header);
2899 g_object_unref (header);
2901 g_object_unref (iter);
2903 if (src_folder == NULL) {
2904 /* Notify the queue */
2905 modest_mail_operation_notify_end (self);
2907 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2912 /* Check folder source and destination */
2913 if (src_folder == folder) {
2914 /* Set status failed and set an error */
2915 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2916 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2917 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2918 _("mail_in_ui_folder_copy_target_error"));
2920 /* Notify the queue */
2921 modest_mail_operation_notify_end (self);
2924 g_object_unref (src_folder);
2928 /* Create the helper */
2929 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2930 helper->mail_op = g_object_ref(self);
2931 helper->dest_folder = g_object_ref(folder);
2932 helper->user_callback = user_callback;
2933 helper->user_data = user_data;
2934 helper->last_total_bytes = 0;
2935 helper->sum_total_bytes = 0;
2936 helper->total_bytes = compute_message_list_size (headers);
2938 /* Get account and set it into mail_operation */
2939 priv->account = modest_tny_folder_get_account (src_folder);
2940 dst_account = modest_tny_folder_get_account (folder);
2942 if (priv->account == dst_account) {
2943 /* Transfer all messages at once using the fast
2944 * method. Note that depending on the server this
2945 * might not be that fast, and might not be
2946 * user-cancellable either */
2947 helper->headers = g_object_ref (headers);
2948 helper->more_msgs = NULL;
2950 /* Transfer messages one by one so the user can cancel
2953 helper->headers = tny_simple_list_new ();
2954 helper->more_msgs = tny_list_create_iterator (headers);
2955 hdr = tny_iterator_get_current (helper->more_msgs);
2956 tny_list_append (helper->headers, hdr);
2957 g_object_unref (hdr);
2960 /* If leave_on_server is set to TRUE then don't use
2961 delete_original, we always pass FALSE. This is because
2962 otherwise tinymail will try to sync the source folder and
2963 this could cause an error if we're offline while
2964 transferring an already downloaded message from a POP
2966 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2967 MODEST_PROTOCOL_STORE_POP) {
2968 const gchar *account_name;
2970 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2971 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2974 leave_on_server = FALSE;
2977 /* Do not delete messages if leave on server is TRUE */
2978 helper->delete = (leave_on_server) ? FALSE : delete_original;
2980 modest_mail_operation_notify_start (self);
2982 /* Start notifying progress */
2983 state = modest_mail_operation_clone_state (self);
2986 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2987 g_slice_free (ModestMailOperationState, state);
2989 tny_folder_transfer_msgs_async (src_folder,
2994 transfer_msgs_status_cb,
2996 g_object_unref (src_folder);
2997 g_object_unref (dst_account);
3002 on_refresh_folder (TnyFolder *folder,
3007 RefreshAsyncHelper *helper = NULL;
3008 ModestMailOperation *self = NULL;
3009 ModestMailOperationPrivate *priv = NULL;
3011 helper = (RefreshAsyncHelper *) user_data;
3012 self = helper->mail_op;
3013 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3015 g_return_if_fail(priv!=NULL);
3018 priv->error = g_error_copy (error);
3019 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3024 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3025 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3026 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3027 _("Error trying to refresh the contents of %s"),
3028 tny_folder_get_name (folder));
3032 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3035 /* Call user defined callback, if it exists */
3036 if (helper->user_callback) {
3038 /* This is not a GDK lock because we are a Tinymail callback and
3039 * Tinymail already acquires the Gdk lock */
3040 helper->user_callback (self, folder, helper->user_data);
3044 g_slice_free (RefreshAsyncHelper, helper);
3046 /* Notify about operation end */
3047 modest_mail_operation_notify_end (self);
3048 g_object_unref(self);
3052 on_refresh_folder_status_update (GObject *obj,
3056 RefreshAsyncHelper *helper = NULL;
3057 ModestMailOperation *self = NULL;
3058 ModestMailOperationPrivate *priv = NULL;
3059 ModestMailOperationState *state;
3061 g_return_if_fail (user_data != NULL);
3062 g_return_if_fail (status != NULL);
3064 /* Show only the status information we want */
3065 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3068 helper = (RefreshAsyncHelper *) user_data;
3069 self = helper->mail_op;
3070 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3072 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3074 priv->done = status->position;
3075 priv->total = status->of_total;
3077 state = modest_mail_operation_clone_state (self);
3079 /* This is not a GDK lock because we are a Tinymail callback and
3080 * Tinymail already acquires the Gdk lock */
3081 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3083 g_slice_free (ModestMailOperationState, state);
3087 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3089 RefreshAsyncUserCallback user_callback,
3092 ModestMailOperationPrivate *priv = NULL;
3093 RefreshAsyncHelper *helper = NULL;
3095 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3097 /* Check memory low */
3098 if (_check_memory_low (self)) {
3100 user_callback (self, folder, user_data);
3101 /* Notify about operation end */
3102 modest_mail_operation_notify_end (self);
3106 /* Get account and set it into mail_operation */
3107 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3108 priv->account = modest_tny_folder_get_account (folder);
3109 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3111 /* Create the helper */
3112 helper = g_slice_new0 (RefreshAsyncHelper);
3113 helper->mail_op = g_object_ref(self);
3114 helper->user_callback = user_callback;
3115 helper->user_data = user_data;
3117 modest_mail_operation_notify_start (self);
3119 /* notify that the operation was started */
3120 ModestMailOperationState *state;
3121 state = modest_mail_operation_clone_state (self);
3124 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3127 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3129 tny_folder_refresh_async (folder,
3131 on_refresh_folder_status_update,
3136 run_queue_stop (ModestTnySendQueue *queue,
3137 ModestMailOperation *self)
3139 ModestMailOperationPrivate *priv;
3141 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3142 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3145 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3147 modest_mail_operation_notify_end (self);
3148 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3149 g_object_unref (self);
3153 modest_mail_operation_run_queue (ModestMailOperation *self,
3154 ModestTnySendQueue *queue)
3156 ModestMailOperationPrivate *priv;
3158 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3159 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3160 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3162 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3163 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3164 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3166 modest_mail_operation_notify_start (self);
3167 g_object_ref (self);
3168 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3172 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3174 ModestMailOperation *self = (ModestMailOperation *) userdata;
3175 ModestMailOperationPrivate *priv;
3177 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3178 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3179 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3181 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3183 modest_mail_operation_notify_end (self);
3184 g_object_unref (self);
3188 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3190 ModestMailOperationPrivate *priv;
3192 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3193 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3194 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3196 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3198 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3199 priv->account = NULL;
3200 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3202 modest_mail_operation_notify_start (self);
3203 g_object_ref (self);
3204 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3208 sync_folder_finish_callback (TnyFolder *self,
3214 ModestMailOperation *mail_op;
3215 ModestMailOperationPrivate *priv;
3217 mail_op = (ModestMailOperation *) user_data;
3218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3220 /* If canceled by the user, ignore the error given by Tinymail */
3222 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3224 /* If the operation was a sync then the status is
3225 failed, but if it's part of another operation then
3226 just set it as finished with errors */
3227 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3228 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3230 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3231 priv->error = g_error_copy ((const GError *) err);
3232 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3234 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3237 modest_mail_operation_notify_end (mail_op);
3238 g_object_unref (mail_op);
3242 modest_mail_operation_sync_folder (ModestMailOperation *self,
3243 TnyFolder *folder, gboolean expunge)
3245 ModestMailOperationPrivate *priv;
3247 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3248 g_return_if_fail (TNY_IS_FOLDER (folder));
3249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3251 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3252 priv->account = modest_tny_folder_get_account (folder);
3253 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3255 modest_mail_operation_notify_start (self);
3256 g_object_ref (self);
3257 tny_folder_sync_async (folder, expunge,
3258 (TnyFolderCallback) sync_folder_finish_callback,
3263 modest_mail_operation_notify_start (ModestMailOperation *self)
3265 ModestMailOperationPrivate *priv = NULL;
3267 g_return_if_fail (self);
3269 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3271 /* Ensure that all the fields are filled correctly */
3272 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3274 /* Notify the observers about the mail operation. We do not
3275 wrapp this emission because we assume that this function is
3276 always called from within the main lock */
3277 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3282 * It's used by the mail operation queue to notify the observers
3283 * attached to that signal that the operation finished. We need to use
3284 * that because tinymail does not give us the progress of a given
3285 * operation when it finishes (it directly calls the operation
3289 modest_mail_operation_notify_end (ModestMailOperation *self)
3291 ModestMailOperationPrivate *priv = NULL;
3293 g_return_if_fail (self);
3295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3297 /* Notify the observers about the mail operation end. We do
3298 not wrapp this emission because we assume that this
3299 function is always called from within the main lock */
3300 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3302 /* Remove the error user data */
3303 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3304 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3308 modest_mail_operation_get_account (ModestMailOperation *self)
3310 ModestMailOperationPrivate *priv = NULL;
3312 g_return_val_if_fail (self, NULL);
3314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3316 return (priv->account) ? g_object_ref (priv->account) : NULL;
3320 modest_mail_operation_noop (ModestMailOperation *self)
3322 ModestMailOperationPrivate *priv = NULL;
3324 g_return_if_fail (self);
3326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3327 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3328 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3332 /* This mail operation does nothing actually */
3333 modest_mail_operation_notify_start (self);
3334 modest_mail_operation_notify_end (self);
3339 modest_mail_operation_to_string (ModestMailOperation *self)
3341 const gchar *type, *status, *account_id;
3342 ModestMailOperationPrivate *priv = NULL;
3344 g_return_val_if_fail (self, NULL);
3346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3348 /* new operations don't have anything interesting */
3349 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3350 return g_strdup_printf ("%p <new operation>", self);
3352 switch (priv->op_type) {
3353 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3354 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3355 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3356 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3357 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3358 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3359 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3360 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3361 default: type = "UNEXPECTED"; break;
3364 switch (priv->status) {
3365 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3366 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3367 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3368 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3369 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3370 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3371 default: status= "UNEXPECTED"; break;
3374 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3376 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3377 priv->done, priv->total,
3378 priv->error && priv->error->message ? priv->error->message : "");
3382 * Once the mail operations were objects this will be no longer
3383 * needed. I don't like it, but we need it for the moment
3386 _check_memory_low (ModestMailOperation *mail_op)
3388 if (modest_platform_check_memory_low (NULL, FALSE)) {
3389 ModestMailOperationPrivate *priv;
3391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3392 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3393 g_set_error (&(priv->error),
3394 MODEST_MAIL_OPERATION_ERROR,
3395 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3396 "Not enough memory to complete the operation");