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 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
520 modest_mail_operation_get_task_done (ModestMailOperation *self)
522 ModestMailOperationPrivate *priv;
524 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
527 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
532 modest_mail_operation_get_task_total (ModestMailOperation *self)
534 ModestMailOperationPrivate *priv;
536 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
539 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
544 modest_mail_operation_is_finished (ModestMailOperation *self)
546 ModestMailOperationPrivate *priv;
547 gboolean retval = FALSE;
549 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
552 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
554 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
555 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
556 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
557 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
567 * Creates an image of the current state of a mail operation, the
568 * caller must free it
570 static ModestMailOperationState *
571 modest_mail_operation_clone_state (ModestMailOperation *self)
573 ModestMailOperationState *state;
574 ModestMailOperationPrivate *priv;
576 /* FIXME: this should be fixed properly
578 * in some cases, priv was NULL, so checking here to
581 g_return_val_if_fail (self, NULL);
582 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
583 g_return_val_if_fail (priv, NULL);
588 state = g_slice_new (ModestMailOperationState);
590 state->status = priv->status;
591 state->op_type = priv->op_type;
592 state->done = priv->done;
593 state->total = priv->total;
594 state->finished = modest_mail_operation_is_finished (self);
595 state->bytes_done = 0;
596 state->bytes_total = 0;
601 /* ******************************************************************* */
602 /* ************************** SEND ACTIONS ************************* */
603 /* ******************************************************************* */
606 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
612 ModestMailOperationPrivate *priv;
613 ModestMailOperation *self;
615 self = MODEST_MAIL_OPERATION (user_data);
616 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
618 if (cancelled || err)
622 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
623 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
624 "Error adding a msg to the send queue\n");
625 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
627 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
630 modest_mail_operation_notify_end (self);
631 g_object_unref (self);
635 modest_mail_operation_send_mail (ModestMailOperation *self,
636 TnyTransportAccount *transport_account,
639 TnySendQueue *send_queue = NULL;
640 ModestMailOperationPrivate *priv;
642 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
643 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
644 g_return_if_fail (msg && TNY_IS_MSG (msg));
646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
648 /* Get account and set it into mail_operation */
649 priv->account = g_object_ref (transport_account);
650 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
654 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
655 if (!TNY_IS_SEND_QUEUE(send_queue)) {
657 g_error_free (priv->error);
660 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
661 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
662 "modest: could not find send queue for account\n");
663 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
664 modest_mail_operation_notify_end (self);
666 modest_mail_operation_notify_start (self);
667 /* Add the msg to the queue. The callback will
668 finalize the mail operation */
669 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
670 NULL, g_object_ref (self));
671 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
678 idle_create_msg_cb (gpointer idle_data)
680 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
682 /* This is a GDK lock because we are an idle callback and
683 * info->callback can contain Gtk+ code */
685 gdk_threads_enter (); /* CHECKED */
686 info->callback (info->mail_op, info->msg, info->userdata);
688 g_object_unref (info->mail_op);
690 g_object_unref (info->msg);
691 g_slice_free (CreateMsgIdleInfo, info);
692 gdk_threads_leave (); /* CHECKED */
698 create_msg_thread (gpointer thread_data)
700 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
701 TnyMsg *new_msg = NULL;
702 ModestMailOperationPrivate *priv;
704 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
705 if (info->html_body == NULL) {
706 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
707 info->bcc, info->subject, info->plain_body,
708 info->attachments_list,
711 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
712 info->bcc, info->subject, info->html_body,
713 info->plain_body, info->attachments_list,
721 /* Set priority flags in message */
722 header = tny_msg_get_header (new_msg);
723 tny_header_set_flag (header, info->priority_flags);
725 /* Set attachment flags in message */
726 if (info->attachments_list != NULL)
727 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
729 g_object_unref (G_OBJECT(header));
731 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
733 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
734 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
735 "modest: failed to create a new msg\n");
743 g_free (info->plain_body);
744 g_free (info->html_body);
745 g_free (info->subject);
746 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
747 g_list_free (info->attachments_list);
748 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
749 g_list_free (info->images_list);
751 if (info->callback) {
752 CreateMsgIdleInfo *idle_info;
753 idle_info = g_slice_new0 (CreateMsgIdleInfo);
754 idle_info->mail_op = g_object_ref (info->mail_op);
755 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
756 idle_info->callback = info->callback;
757 idle_info->userdata = info->userdata;
758 g_idle_add (idle_create_msg_cb, idle_info);
760 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
763 g_object_unref (info->mail_op);
764 g_slice_free (CreateMsgInfo, info);
765 if (new_msg) g_object_unref(new_msg);
771 modest_mail_operation_create_msg (ModestMailOperation *self,
772 const gchar *from, const gchar *to,
773 const gchar *cc, const gchar *bcc,
774 const gchar *subject, const gchar *plain_body,
775 const gchar *html_body,
776 const GList *attachments_list,
777 const GList *images_list,
778 TnyHeaderFlags priority_flags,
779 ModestMailOperationCreateMsgCallback callback,
782 CreateMsgInfo *info = NULL;
784 info = g_slice_new0 (CreateMsgInfo);
785 info->mail_op = g_object_ref (self);
787 info->from = g_strdup (from);
788 info->to = g_strdup (to);
789 info->cc = g_strdup (cc);
790 info->bcc = g_strdup (bcc);
791 info->subject = g_strdup (subject);
792 info->plain_body = g_strdup (plain_body);
793 info->html_body = g_strdup (html_body);
794 info->attachments_list = g_list_copy ((GList *) attachments_list);
795 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
796 info->images_list = g_list_copy ((GList *) images_list);
797 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
798 info->priority_flags = priority_flags;
800 info->callback = callback;
801 info->userdata = userdata;
803 g_thread_create (create_msg_thread, info, FALSE, NULL);
808 TnyTransportAccount *transport_account;
813 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
817 ModestMailOperationPrivate *priv = NULL;
818 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
819 TnyFolder *draft_folder = NULL;
820 TnyFolder *outbox_folder = NULL;
821 TnyHeader *header = NULL;
823 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
827 modest_mail_operation_notify_end (self);
831 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
832 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
833 modest_mail_operation_notify_end (self);
837 /* Call mail operation */
838 modest_mail_operation_send_mail (self, info->transport_account, msg);
840 if (info->draft_msg != NULL) {
841 TnyList *tmp_headers = NULL;
842 TnyFolder *folder = NULL;
843 TnyFolder *src_folder = NULL;
844 TnyFolderType folder_type;
845 TnyTransportAccount *transport_account = NULL;
847 /* To remove the old mail from its source folder, we need to get the
848 * transport account of the original draft message (the transport account
849 * might have been changed by the user) */
850 header = tny_msg_get_header (info->draft_msg);
851 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
852 modest_runtime_get_account_store(), header);
853 if (transport_account == NULL)
854 transport_account = g_object_ref(info->transport_account);
855 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
856 TNY_FOLDER_TYPE_DRAFTS);
857 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
858 TNY_FOLDER_TYPE_OUTBOX);
859 g_object_unref(transport_account);
862 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
866 if (!outbox_folder) {
867 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
872 folder = tny_msg_get_folder (info->draft_msg);
873 if (folder == NULL) goto end;
874 folder_type = modest_tny_folder_guess_folder_type (folder);
876 if (folder_type == TNY_FOLDER_TYPE_INVALID)
877 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
879 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
880 src_folder = outbox_folder;
882 src_folder = draft_folder;
884 /* Note: This can fail (with a warning) if the message is not really already in a folder,
885 * because this function requires it to have a UID. */
886 tmp_headers = tny_simple_list_new ();
887 tny_list_append (tmp_headers, (GObject*) header);
888 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
889 g_object_unref (tmp_headers);
890 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
892 g_object_unref (folder);
897 g_object_unref (header);
899 g_object_unref (info->draft_msg);
901 g_object_unref (draft_folder);
903 g_object_unref (outbox_folder);
904 if (info->transport_account)
905 g_object_unref (info->transport_account);
906 g_slice_free (SendNewMailInfo, info);
910 modest_mail_operation_send_new_mail (ModestMailOperation *self,
911 TnyTransportAccount *transport_account,
913 const gchar *from, const gchar *to,
914 const gchar *cc, const gchar *bcc,
915 const gchar *subject, const gchar *plain_body,
916 const gchar *html_body,
917 const GList *attachments_list,
918 const GList *images_list,
919 TnyHeaderFlags priority_flags)
921 ModestMailOperationPrivate *priv = NULL;
922 SendNewMailInfo *info;
924 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
925 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
928 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
929 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
930 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
932 /* Check parametters */
934 /* Set status failed and set an error */
935 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
936 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
937 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
938 _("Error trying to send a mail. You need to set at least one recipient"));
941 info = g_slice_new0 (SendNewMailInfo);
942 info->transport_account = transport_account;
943 if (transport_account)
944 g_object_ref (transport_account);
945 info->draft_msg = draft_msg;
947 g_object_ref (draft_msg);
950 modest_mail_operation_notify_start (self);
951 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
952 attachments_list, images_list, priority_flags,
953 modest_mail_operation_send_new_mail_cb, info);
959 TnyTransportAccount *transport_account;
961 SaveToDraftstCallback callback;
965 ModestMailOperation *mailop;
966 } SaveToDraftsAddMsgInfo;
969 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
974 ModestMailOperationPrivate *priv = NULL;
975 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
976 GError *io_error = NULL;
978 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
980 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
981 io_error = priv->error;
985 g_warning ("%s: priv->error != NULL", __FUNCTION__);
986 g_error_free(priv->error);
989 priv->error = (err == NULL) ? NULL : g_error_copy(err);
991 if ((!priv->error) && (info->draft_msg != NULL)) {
992 TnyHeader *header = tny_msg_get_header (info->draft_msg);
993 TnyFolder *src_folder = tny_header_get_folder (header);
995 /* Remove the old draft */
996 tny_folder_remove_msg (src_folder, header, NULL);
998 /* Synchronize to expunge and to update the msg counts */
999 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1000 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1002 g_object_unref (G_OBJECT(header));
1003 g_object_unref (G_OBJECT(src_folder));
1007 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1009 g_error_free (io_error);
1012 } else if (io_error) {
1013 priv->error = io_error;
1014 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1016 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1019 /* Call the user callback */
1021 info->callback (info->mailop, info->msg, info->user_data);
1023 if (info->transport_account)
1024 g_object_unref (G_OBJECT(info->transport_account));
1025 if (info->draft_msg)
1026 g_object_unref (G_OBJECT (info->draft_msg));
1028 g_object_unref (G_OBJECT(info->drafts));
1030 g_object_unref (G_OBJECT (info->msg));
1032 modest_mail_operation_notify_end (info->mailop);
1033 g_object_unref(info->mailop);
1034 g_slice_free (SaveToDraftsAddMsgInfo, info);
1039 TnyTransportAccount *transport_account;
1041 SaveToDraftstCallback callback;
1046 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1050 TnyFolder *drafts = NULL;
1051 ModestMailOperationPrivate *priv = NULL;
1052 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1054 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1057 if (!(priv->error)) {
1058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1059 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1060 "modest: failed to create a new msg\n");
1063 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1064 TNY_FOLDER_TYPE_DRAFTS);
1065 if (!drafts && !(priv->error)) {
1066 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1067 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1068 "modest: failed to create a new msg\n");
1072 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1073 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1074 cb_info->transport_account = g_object_ref(info->transport_account);
1075 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1076 cb_info->callback = info->callback;
1077 cb_info->user_data = info->user_data;
1078 cb_info->drafts = g_object_ref(drafts);
1079 cb_info->msg = g_object_ref(msg);
1080 cb_info->mailop = g_object_ref(self);
1081 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1084 /* Call the user callback */
1085 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1087 info->callback (self, msg, info->user_data);
1088 modest_mail_operation_notify_end (self);
1092 g_object_unref (G_OBJECT(drafts));
1093 if (info->draft_msg)
1094 g_object_unref (G_OBJECT (info->draft_msg));
1095 if (info->transport_account)
1096 g_object_unref (G_OBJECT(info->transport_account));
1097 g_slice_free (SaveToDraftsInfo, info);
1101 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1102 TnyTransportAccount *transport_account,
1104 const gchar *from, const gchar *to,
1105 const gchar *cc, const gchar *bcc,
1106 const gchar *subject, const gchar *plain_body,
1107 const gchar *html_body,
1108 const GList *attachments_list,
1109 const GList *images_list,
1110 TnyHeaderFlags priority_flags,
1111 SaveToDraftstCallback callback,
1114 ModestMailOperationPrivate *priv = NULL;
1115 SaveToDraftsInfo *info = NULL;
1117 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1118 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1120 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1122 /* Get account and set it into mail_operation */
1123 priv->account = g_object_ref (transport_account);
1124 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1126 info = g_slice_new0 (SaveToDraftsInfo);
1127 info->transport_account = g_object_ref (transport_account);
1128 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1129 info->callback = callback;
1130 info->user_data = user_data;
1132 modest_mail_operation_notify_start (self);
1133 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1134 attachments_list, images_list, priority_flags,
1135 modest_mail_operation_save_to_drafts_cb, info);
1140 ModestMailOperation *mail_op;
1141 TnyMimePart *mime_part;
1143 GetMimePartSizeCallback callback;
1145 } GetMimePartSizeInfo;
1147 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1148 /* We use this folder observer to track the headers that have been
1149 * added to a folder */
1152 TnyList *new_headers;
1153 } InternalFolderObserver;
1156 GObjectClass parent;
1157 } InternalFolderObserverClass;
1159 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1161 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1162 internal_folder_observer,
1164 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1168 foreach_add_item (gpointer header, gpointer user_data)
1170 tny_list_prepend (TNY_LIST (user_data),
1171 g_object_ref (G_OBJECT (header)));
1174 /* This is the method that looks for new messages in a folder */
1176 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1178 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1180 TnyFolderChangeChanged changed;
1182 changed = tny_folder_change_get_changed (change);
1184 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1187 /* Get added headers */
1188 list = tny_simple_list_new ();
1189 tny_folder_change_get_added_headers (change, list);
1191 /* Add them to the folder observer */
1192 tny_list_foreach (list, foreach_add_item,
1193 derived->new_headers);
1195 g_object_unref (G_OBJECT (list));
1200 internal_folder_observer_init (InternalFolderObserver *self)
1202 self->new_headers = tny_simple_list_new ();
1205 internal_folder_observer_finalize (GObject *object)
1207 InternalFolderObserver *self;
1209 self = (InternalFolderObserver *) object;
1210 g_object_unref (self->new_headers);
1212 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1215 tny_folder_observer_init (TnyFolderObserverIface *iface)
1217 iface->update = internal_folder_observer_update;
1220 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1222 GObjectClass *object_class;
1224 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1225 object_class = (GObjectClass*) klass;
1226 object_class->finalize = internal_folder_observer_finalize;
1231 ModestMailOperation *mail_op;
1232 gchar *account_name;
1233 UpdateAccountCallback callback;
1238 TnyFolderObserver *inbox_observer;
1239 RetrieveAllCallback retrieve_all_cb;
1240 gboolean interactive;
1241 } UpdateAccountInfo;
1245 destroy_update_account_info (UpdateAccountInfo *info)
1247 g_free (info->account_name);
1248 g_object_unref (info->folders);
1249 g_object_unref (info->mail_op);
1250 g_slice_free (UpdateAccountInfo, info);
1254 update_account_get_msg_async_cb (TnyFolder *folder,
1260 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1262 /* Just delete the helper. Don't do anything with the new
1263 msg. There is also no need to check for errors */
1264 g_object_unref (msg_info->mail_op);
1265 g_object_unref (msg_info->header);
1266 g_slice_free (GetMsgInfo, msg_info);
1270 update_account_notify_user_and_free (UpdateAccountInfo *info,
1271 TnyList *new_headers)
1273 /* Set the account back to not busy */
1274 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1275 info->account_name, FALSE);
1279 info->callback (info->mail_op, new_headers, info->user_data);
1281 /* Mail operation end */
1282 modest_mail_operation_notify_end (info->mail_op);
1286 g_object_unref (new_headers);
1287 destroy_update_account_info (info);
1291 inbox_refreshed_cb (TnyFolder *inbox,
1296 UpdateAccountInfo *info;
1297 ModestMailOperationPrivate *priv;
1298 TnyIterator *new_headers_iter;
1299 GPtrArray *new_headers_array = NULL;
1300 gint max_size, retrieve_limit, i;
1301 ModestAccountMgr *mgr;
1302 ModestAccountRetrieveType retrieve_type;
1303 TnyList *new_headers = NULL;
1304 gboolean headers_only, ignore_limit;
1305 TnyTransportAccount *transport_account = NULL;
1307 info = (UpdateAccountInfo *) user_data;
1308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1309 mgr = modest_runtime_get_account_mgr ();
1311 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1312 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1314 if (canceled || err) {
1315 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1317 priv->error = g_error_copy (err);
1319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1320 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1323 /* Notify the user about the error and then exit */
1324 update_account_notify_user_and_free (info, NULL);
1329 /* Try to send anyway */
1333 /* Get the message max size */
1334 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1335 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1337 max_size = G_MAXINT;
1339 max_size = max_size * KB;
1341 /* Create the new headers array. We need it to sort the
1342 new headers by date */
1343 new_headers_array = g_ptr_array_new ();
1344 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1345 while (!tny_iterator_is_done (new_headers_iter)) {
1346 TnyHeader *header = NULL;
1348 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1349 /* Apply per-message size limits */
1350 if (tny_header_get_message_size (header) < max_size)
1351 g_ptr_array_add (new_headers_array, g_object_ref (header));
1353 g_object_unref (header);
1354 tny_iterator_next (new_headers_iter);
1356 g_object_unref (new_headers_iter);
1357 tny_folder_remove_observer (inbox, info->inbox_observer);
1358 g_object_unref (info->inbox_observer);
1359 info->inbox_observer = NULL;
1361 if (new_headers_array->len == 0)
1364 /* Get per-account message amount retrieval limit */
1365 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1366 if (retrieve_limit == 0)
1367 retrieve_limit = G_MAXINT;
1369 /* Get per-account retrieval type */
1370 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1371 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1374 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1376 /* Ask the users if they want to retrieve all the messages
1377 even though the limit was exceeded */
1378 ignore_limit = FALSE;
1379 if (new_headers_array->len > retrieve_limit) {
1380 /* Ask the user if a callback has been specified and
1381 if the mail operation has a source (this means that
1382 was invoked by the user and not automatically by a
1384 if (info->retrieve_all_cb && priv->source)
1385 ignore_limit = info->retrieve_all_cb (priv->source,
1386 new_headers_array->len,
1390 if (!headers_only) {
1392 const gint msg_list_size = compute_message_array_size (new_headers_array);
1396 priv->total = new_headers_array->len;
1398 priv->total = MIN (new_headers_array->len, retrieve_limit);
1399 while (msg_num < priv->total) {
1400 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1401 TnyFolder *folder = tny_header_get_folder (header);
1402 GetMsgInfo *msg_info;
1404 /* Create the message info */
1405 msg_info = g_slice_new0 (GetMsgInfo);
1406 msg_info->mail_op = g_object_ref (info->mail_op);
1407 msg_info->header = g_object_ref (header);
1408 msg_info->total_bytes = msg_list_size;
1410 /* Get message in an async way */
1411 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1412 get_msg_status_cb, msg_info);
1414 g_object_unref (folder);
1420 /* Copy the headers to a list and free the array */
1421 new_headers = tny_simple_list_new ();
1422 for (i=0; i < new_headers_array->len; i++) {
1423 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1424 tny_list_append (new_headers, G_OBJECT (header));
1426 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1427 g_ptr_array_free (new_headers_array, FALSE);
1430 /* Get the transport account */
1431 transport_account = (TnyTransportAccount *)
1432 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1433 info->account_name);
1435 if (transport_account) {
1436 ModestTnySendQueue *send_queue;
1440 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1441 g_object_unref (transport_account);
1443 /* Get outbox folder */
1444 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1445 if (outbox) { /* this could fail in some cases */
1446 num_messages = tny_folder_get_all_count (outbox);
1447 g_object_unref (outbox);
1449 g_warning ("%s: could not get outbox", __FUNCTION__);
1453 if (num_messages != 0) {
1454 /* Reenable suspended items */
1455 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1458 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1459 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1464 /* Check if the operation was a success */
1466 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1468 /* Call the user callback and free */
1469 update_account_notify_user_and_free (info, new_headers);
1473 inbox_refresh_status_update (GObject *obj,
1477 UpdateAccountInfo *info = NULL;
1478 ModestMailOperation *self = NULL;
1479 ModestMailOperationPrivate *priv = NULL;
1480 ModestMailOperationState *state;
1482 g_return_if_fail (user_data != NULL);
1483 g_return_if_fail (status != NULL);
1485 /* Show only the status information we want */
1486 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1489 info = (UpdateAccountInfo *) user_data;
1490 self = info->mail_op;
1491 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1493 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1495 priv->done = status->position;
1496 priv->total = status->of_total;
1498 state = modest_mail_operation_clone_state (self);
1500 /* This is not a GDK lock because we are a Tinymail callback and
1501 * Tinymail already acquires the Gdk lock */
1502 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1504 g_slice_free (ModestMailOperationState, state);
1508 recurse_folders_async_cb (TnyFolderStore *folder_store,
1514 UpdateAccountInfo *info;
1515 ModestMailOperationPrivate *priv;
1517 info = (UpdateAccountInfo *) user_data;
1518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1520 if (err || canceled) {
1521 /* If the error was previosly set by another callback
1522 don't set it again */
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1526 priv->error = g_error_copy (err);
1528 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1529 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1533 /* We're not getting INBOX children if we don't want to poke all */
1534 TnyIterator *iter = tny_list_create_iterator (list);
1535 while (!tny_iterator_is_done (iter)) {
1536 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1538 /* Add to the list of all folders */
1539 tny_list_append (info->folders, (GObject *) folder);
1541 if (info->poke_all) {
1542 TnyList *folders = tny_simple_list_new ();
1543 /* Add pending call */
1544 info->pending_calls++;
1546 tny_folder_store_get_folders_async (folder, folders, NULL,
1547 recurse_folders_async_cb,
1549 g_object_unref (folders);
1552 g_object_unref (G_OBJECT (folder));
1554 tny_iterator_next (iter);
1556 g_object_unref (G_OBJECT (iter));
1559 /* Remove my own pending call */
1560 info->pending_calls--;
1562 /* This means that we have all the folders */
1563 if (info->pending_calls == 0) {
1564 TnyIterator *iter_all_folders;
1565 TnyFolder *inbox = NULL;
1567 /* If there was any error do not continue */
1569 update_account_notify_user_and_free (info, NULL);
1573 iter_all_folders = tny_list_create_iterator (info->folders);
1575 /* Do a poke status over all folders */
1576 while (!tny_iterator_is_done (iter_all_folders) &&
1577 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1578 TnyFolder *folder = NULL;
1580 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1582 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1583 /* Get a reference to the INBOX */
1584 inbox = g_object_ref (folder);
1586 /* Issue a poke status over the folder */
1588 tny_folder_poke_status (folder);
1591 /* Free and go to next */
1592 g_object_unref (folder);
1593 tny_iterator_next (iter_all_folders);
1595 g_object_unref (iter_all_folders);
1597 /* Refresh the INBOX */
1599 /* Refresh the folder. Our observer receives
1600 * the new emails during folder refreshes, so
1601 * we can use observer->new_headers
1603 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1604 tny_folder_add_observer (inbox, info->inbox_observer);
1606 /* Refresh the INBOX */
1607 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1608 g_object_unref (inbox);
1610 /* We could not perform the inbox refresh but
1611 we'll try to send mails anyway */
1612 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1618 modest_mail_operation_update_account (ModestMailOperation *self,
1619 const gchar *account_name,
1621 gboolean interactive,
1622 RetrieveAllCallback retrieve_all_cb,
1623 UpdateAccountCallback callback,
1626 UpdateAccountInfo *info = NULL;
1627 ModestMailOperationPrivate *priv = NULL;
1628 ModestTnyAccountStore *account_store = NULL;
1630 ModestMailOperationState *state;
1632 /* Init mail operation */
1633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1636 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1637 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1639 /* Get the store account */
1640 account_store = modest_runtime_get_account_store ();
1642 modest_tny_account_store_get_server_account (account_store,
1644 TNY_ACCOUNT_TYPE_STORE);
1646 /* The above function could return NULL */
1647 if (!priv->account) {
1648 /* Check if the operation was a success */
1649 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1650 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1654 /* Call the user callback */
1656 callback (self, NULL, user_data);
1658 /* Notify about operation end */
1659 modest_mail_operation_notify_end (self);
1664 /* We have once seen priv->account getting finalized during this code,
1665 * therefore adding a reference (bug #82296) */
1667 g_object_ref (priv->account);
1669 /* Create the helper object */
1670 info = g_slice_new0 (UpdateAccountInfo);
1671 info->pending_calls = 1;
1672 info->folders = tny_simple_list_new ();
1673 info->mail_op = g_object_ref (self);
1674 info->poke_all = poke_all;
1675 info->interactive = interactive;
1676 info->account_name = g_strdup (account_name);
1677 info->callback = callback;
1678 info->user_data = user_data;
1679 info->retrieve_all_cb = retrieve_all_cb;
1681 /* Set account busy */
1682 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1683 modest_mail_operation_notify_start (self);
1685 /* notify about the start of the operation */
1686 state = modest_mail_operation_clone_state (self);
1690 /* Start notifying progress */
1691 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1692 g_slice_free (ModestMailOperationState, state);
1694 /* Get all folders and continue in the callback */
1695 folders = tny_simple_list_new ();
1696 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1698 recurse_folders_async_cb,
1700 g_object_unref (folders);
1702 g_object_unref (priv->account);
1707 * Used to notify the queue from the main
1708 * loop. We call it inside an idle call to achieve that
1711 idle_notify_queue (gpointer data)
1713 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1715 gdk_threads_enter ();
1716 modest_mail_operation_notify_end (mail_op);
1717 gdk_threads_leave ();
1718 g_object_unref (mail_op);
1724 compare_headers_by_date (gconstpointer a,
1727 TnyHeader **header1, **header2;
1728 time_t sent1, sent2;
1730 header1 = (TnyHeader **) a;
1731 header2 = (TnyHeader **) b;
1733 sent1 = tny_header_get_date_sent (*header1);
1734 sent2 = tny_header_get_date_sent (*header2);
1736 /* We want the most recent ones (greater time_t) at the
1745 /* ******************************************************************* */
1746 /* ************************** STORE ACTIONS ************************* */
1747 /* ******************************************************************* */
1750 ModestMailOperation *mail_op;
1751 CreateFolderUserCallback callback;
1757 create_folder_cb (TnyFolderStore *parent_folder,
1759 TnyFolder *new_folder,
1763 ModestMailOperationPrivate *priv;
1764 CreateFolderInfo *info;
1766 info = (CreateFolderInfo *) user_data;
1767 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1769 if (canceled || err) {
1770 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1772 priv->error = g_error_copy (err);
1774 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1775 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1778 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1781 /* The user will unref the new_folder */
1783 info->callback (info->mail_op, parent_folder,
1784 new_folder, info->user_data);
1786 /* Notify about operation end */
1787 modest_mail_operation_notify_end (info->mail_op);
1790 g_object_unref (info->mail_op);
1791 g_slice_free (CreateFolderInfo, info);
1795 modest_mail_operation_create_folder (ModestMailOperation *self,
1796 TnyFolderStore *parent,
1798 CreateFolderUserCallback callback,
1801 ModestMailOperationPrivate *priv;
1803 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1804 g_return_if_fail (name);
1806 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1807 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1808 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1809 g_object_ref (parent) :
1810 modest_tny_folder_get_account (TNY_FOLDER (parent));
1812 /* Check for already existing folder */
1813 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1814 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1815 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1816 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1817 _CS("ckdg_ib_folder_already_exists"));
1821 if (TNY_IS_FOLDER (parent)) {
1822 /* Check folder rules */
1823 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1824 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1825 /* Set status failed and set an error */
1826 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1827 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1828 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1829 _("mail_in_ui_folder_create_error"));
1833 if (!strcmp (name, " ") || strchr (name, '/')) {
1834 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1835 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1836 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1837 _("mail_in_ui_folder_create_error"));
1841 CreateFolderInfo *info;
1843 info = g_slice_new0 (CreateFolderInfo);
1844 info->mail_op = g_object_ref (self);
1845 info->callback = callback;
1846 info->user_data = user_data;
1848 modest_mail_operation_notify_start (self);
1850 /* Create the folder */
1851 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1854 /* Call the user callback anyway */
1856 callback (self, parent, NULL, user_data);
1857 /* Notify about operation end */
1858 modest_mail_operation_notify_end (self);
1863 modest_mail_operation_remove_folder (ModestMailOperation *self,
1865 gboolean remove_to_trash)
1867 ModestMailOperationPrivate *priv;
1868 ModestTnyFolderRules rules;
1870 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1871 g_return_if_fail (TNY_IS_FOLDER (folder));
1873 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1875 /* Check folder rules */
1876 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1877 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1878 /* Set status failed and set an error */
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1881 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1882 _("mail_in_ui_folder_delete_error"));
1886 /* Get the account */
1887 priv->account = modest_tny_folder_get_account (folder);
1888 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1890 /* Delete folder or move to trash */
1891 if (remove_to_trash) {
1892 TnyFolder *trash_folder = NULL;
1893 trash_folder = modest_tny_account_get_special_folder (priv->account,
1894 TNY_FOLDER_TYPE_TRASH);
1895 /* TODO: error_handling */
1897 modest_mail_operation_notify_start (self);
1898 modest_mail_operation_xfer_folder (self, folder,
1899 TNY_FOLDER_STORE (trash_folder),
1901 g_object_unref (trash_folder);
1903 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1906 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1908 modest_mail_operation_notify_start (self);
1909 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1910 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1913 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1915 g_object_unref (parent);
1917 g_warning ("%s: could not get parent folder", __FUNCTION__);
1921 /* Notify about operation end */
1922 modest_mail_operation_notify_end (self);
1926 transfer_folder_status_cb (GObject *obj,
1930 ModestMailOperation *self;
1931 ModestMailOperationPrivate *priv;
1932 ModestMailOperationState *state;
1933 XFerFolderAsyncHelper *helper;
1935 g_return_if_fail (status != NULL);
1937 /* Show only the status information we want */
1938 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1941 helper = (XFerFolderAsyncHelper *) user_data;
1942 g_return_if_fail (helper != NULL);
1944 self = helper->mail_op;
1945 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1947 priv->done = status->position;
1948 priv->total = status->of_total;
1950 state = modest_mail_operation_clone_state (self);
1952 /* This is not a GDK lock because we are a Tinymail callback
1953 * which is already GDK locked by Tinymail */
1955 /* no gdk_threads_enter (), CHECKED */
1957 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1959 /* no gdk_threads_leave (), CHECKED */
1961 g_slice_free (ModestMailOperationState, state);
1966 transfer_folder_cb (TnyFolder *folder,
1968 TnyFolderStore *into,
1969 TnyFolder *new_folder,
1973 XFerFolderAsyncHelper *helper;
1974 ModestMailOperation *self = NULL;
1975 ModestMailOperationPrivate *priv = NULL;
1977 helper = (XFerFolderAsyncHelper *) user_data;
1978 g_return_if_fail (helper != NULL);
1980 self = helper->mail_op;
1981 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1984 priv->error = g_error_copy (err);
1986 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1987 } else if (cancelled) {
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1990 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1991 _("Transference of %s was cancelled."),
1992 tny_folder_get_name (folder));
1995 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1998 /* Notify about operation end */
1999 modest_mail_operation_notify_end (self);
2001 /* If user defined callback function was defined, call it */
2002 if (helper->user_callback) {
2004 /* This is not a GDK lock because we are a Tinymail callback
2005 * which is already GDK locked by Tinymail */
2007 /* no gdk_threads_enter (), CHECKED */
2008 helper->user_callback (self, new_folder, helper->user_data);
2009 /* no gdk_threads_leave () , CHECKED */
2013 g_object_unref (helper->mail_op);
2014 g_slice_free (XFerFolderAsyncHelper, helper);
2019 * This function checks if the new name is a valid name for our local
2020 * folders account. The new name could not be the same than then name
2021 * of any of the mandatory local folders
2023 * We can not rely on tinymail because tinymail does not check the
2024 * name of the virtual folders that the account could have in the case
2025 * that we're doing a rename (because it directly calls Camel which
2026 * knows nothing about our virtual folders).
2028 * In the case of an actual copy/move (i.e. move/copy a folder between
2029 * accounts) tinymail uses the tny_folder_store_create_account which
2030 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2031 * checks the new name of the folder, so this call in that case
2032 * wouldn't be needed. *But* NOTE that if tinymail changes its
2033 * implementation (if folder transfers within the same account is no
2034 * longer implemented as a rename) this call will allow Modest to work
2037 * If the new name is not valid, this function will set the status to
2038 * failed and will set also an error in the mail operation
2041 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2042 TnyFolderStore *into,
2043 const gchar *new_name)
2045 if (TNY_IS_ACCOUNT (into) &&
2046 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2047 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2049 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2050 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2051 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2052 _CS("ckdg_ib_folder_already_exists"));
2059 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2061 TnyFolderStore *parent,
2062 gboolean delete_original,
2063 XferFolderAsyncUserCallback user_callback,
2066 ModestMailOperationPrivate *priv = NULL;
2067 ModestTnyFolderRules parent_rules = 0, rules;
2068 XFerFolderAsyncHelper *helper = NULL;
2069 const gchar *folder_name = NULL;
2070 const gchar *error_msg;
2072 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2073 g_return_if_fail (TNY_IS_FOLDER (folder));
2074 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2076 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2077 folder_name = tny_folder_get_name (folder);
2079 /* Set the error msg */
2080 error_msg = _("mail_in_ui_folder_move_target_error");
2082 /* Get account and set it into mail_operation */
2083 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2084 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2085 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2087 /* Get folder rules */
2088 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2089 if (TNY_IS_FOLDER (parent))
2090 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2092 /* Apply operation constraints */
2093 if ((gpointer) parent == (gpointer) folder ||
2094 (!TNY_IS_FOLDER_STORE (parent)) ||
2095 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2098 } else if (TNY_IS_FOLDER (parent) &&
2099 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2103 } else if (TNY_IS_FOLDER (parent) &&
2104 TNY_IS_FOLDER_STORE (folder) &&
2105 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2106 TNY_FOLDER_STORE (folder))) {
2107 /* Do not move a parent into a child */
2109 } else if (TNY_IS_FOLDER_STORE (parent) &&
2110 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2111 /* Check that the new folder name is not used by any
2114 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2115 /* Check that the new folder name is not used by any
2116 special local folder */
2119 /* Create the helper */
2120 helper = g_slice_new0 (XFerFolderAsyncHelper);
2121 helper->mail_op = g_object_ref (self);
2122 helper->user_callback = user_callback;
2123 helper->user_data = user_data;
2125 /* Move/Copy folder */
2126 modest_mail_operation_notify_start (self);
2127 tny_folder_copy_async (folder,
2129 tny_folder_get_name (folder),
2132 transfer_folder_status_cb,
2138 /* Set status failed and set an error */
2139 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2140 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2141 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2144 /* Call the user callback if exists */
2146 user_callback (self, NULL, user_data);
2148 /* Notify the queue */
2149 modest_mail_operation_notify_end (self);
2153 modest_mail_operation_rename_folder (ModestMailOperation *self,
2156 XferFolderAsyncUserCallback user_callback,
2159 ModestMailOperationPrivate *priv;
2160 ModestTnyFolderRules rules;
2161 XFerFolderAsyncHelper *helper;
2163 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2164 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2165 g_return_if_fail (name);
2167 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2169 /* Get account and set it into mail_operation */
2170 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2171 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2173 /* Check folder rules */
2174 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2175 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2177 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2180 TnyFolderStore *into;
2182 into = tny_folder_get_folder_store (folder);
2184 /* Check that the new folder name is not used by any
2185 special local folder */
2186 if (new_name_valid_if_local_account (priv, into, name)) {
2187 /* Create the helper */
2188 helper = g_slice_new0 (XFerFolderAsyncHelper);
2189 helper->mail_op = g_object_ref(self);
2190 helper->user_callback = user_callback;
2191 helper->user_data = user_data;
2193 /* Rename. Camel handles folder subscription/unsubscription */
2194 modest_mail_operation_notify_start (self);
2195 tny_folder_copy_async (folder, into, name, TRUE,
2197 transfer_folder_status_cb,
2199 g_object_unref (into);
2201 g_object_unref (into);
2208 /* Set status failed and set an error */
2209 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2210 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2211 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2212 _("FIXME: unable to rename"));
2215 user_callback (self, NULL, user_data);
2217 /* Notify about operation end */
2218 modest_mail_operation_notify_end (self);
2221 /* ******************************************************************* */
2222 /* ************************** MSG ACTIONS ************************* */
2223 /* ******************************************************************* */
2226 modest_mail_operation_get_msg (ModestMailOperation *self,
2228 gboolean progress_feedback,
2229 GetMsgAsyncUserCallback user_callback,
2232 GetMsgInfo *helper = NULL;
2234 ModestMailOperationPrivate *priv;
2236 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2237 g_return_if_fail (TNY_IS_HEADER (header));
2239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2240 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2244 /* Check memory low */
2245 if (_check_memory_low (self)) {
2247 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2248 modest_mail_operation_notify_end (self);
2252 /* Get account and set it into mail_operation */
2253 folder = tny_header_get_folder (header);
2254 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2256 /* Check for cached messages */
2257 if (progress_feedback) {
2258 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2259 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2261 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2263 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2266 /* Create the helper */
2267 helper = g_slice_new0 (GetMsgInfo);
2268 helper->header = g_object_ref (header);
2269 helper->mail_op = g_object_ref (self);
2270 helper->user_callback = user_callback;
2271 helper->user_data = user_data;
2272 helper->destroy_notify = NULL;
2273 helper->last_total_bytes = 0;
2274 helper->sum_total_bytes = 0;
2275 helper->total_bytes = tny_header_get_message_size (header);
2276 helper->more_msgs = NULL;
2278 modest_mail_operation_notify_start (self);
2280 /* notify about the start of the operation */
2281 ModestMailOperationState *state;
2282 state = modest_mail_operation_clone_state (self);
2285 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2287 g_slice_free (ModestMailOperationState, state);
2289 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2291 g_object_unref (G_OBJECT (folder));
2295 get_msg_status_cb (GObject *obj,
2299 GetMsgInfo *helper = NULL;
2301 g_return_if_fail (status != NULL);
2303 /* Show only the status information we want */
2304 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2307 helper = (GetMsgInfo *) user_data;
2308 g_return_if_fail (helper != NULL);
2310 /* Notify progress */
2311 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2312 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2316 get_msg_async_cb (TnyFolder *folder,
2322 GetMsgInfo *info = NULL;
2323 ModestMailOperationPrivate *priv = NULL;
2326 info = (GetMsgInfo *) user_data;
2328 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2331 if (info->more_msgs) {
2332 tny_iterator_next (info->more_msgs);
2333 finished = (tny_iterator_is_done (info->more_msgs));
2335 finished = (priv->done == priv->total) ? TRUE : FALSE;
2338 /* If canceled by the user, ignore the error given by Tinymail */
2342 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2344 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2346 priv->error = g_error_copy ((const GError *) err);
2347 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2350 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2351 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2354 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2355 /* Set the success status before calling the user callback */
2356 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2360 /* Call the user callback */
2361 if (info->user_callback)
2362 info->user_callback (info->mail_op, info->header, canceled,
2363 msg, err, info->user_data);
2365 /* Notify about operation end if this is the last callback */
2367 /* Free user data */
2368 if (info->destroy_notify)
2369 info->destroy_notify (info->user_data);
2371 /* Notify about operation end */
2372 modest_mail_operation_notify_end (info->mail_op);
2375 if (info->more_msgs)
2376 g_object_unref (info->more_msgs);
2377 g_object_unref (info->header);
2378 g_object_unref (info->mail_op);
2379 g_slice_free (GetMsgInfo, info);
2380 } else if (info->more_msgs) {
2381 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2382 TnyFolder *folder = tny_header_get_folder (header);
2384 g_object_unref (info->header);
2385 info->header = g_object_ref (header);
2387 /* Retrieve the next message */
2388 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2390 g_object_unref (header);
2391 g_object_unref (folder);
2393 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2398 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2399 TnyList *header_list,
2400 GetMsgAsyncUserCallback user_callback,
2402 GDestroyNotify notify)
2404 ModestMailOperationPrivate *priv = NULL;
2406 TnyIterator *iter = NULL;
2407 gboolean has_uncached_messages;
2409 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2411 /* Init mail operation */
2412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2413 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2415 priv->total = tny_list_get_length(header_list);
2417 /* Check memory low */
2418 if (_check_memory_low (self)) {
2419 if (user_callback) {
2420 TnyHeader *header = NULL;
2423 if (tny_list_get_length (header_list) > 0) {
2424 iter = tny_list_create_iterator (header_list);
2425 header = (TnyHeader *) tny_iterator_get_current (iter);
2426 g_object_unref (iter);
2428 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2430 g_object_unref (header);
2434 /* Notify about operation end */
2435 modest_mail_operation_notify_end (self);
2439 /* Check uncached messages */
2440 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2441 !has_uncached_messages && !tny_iterator_is_done (iter);
2442 tny_iterator_next (iter)) {
2445 header = (TnyHeader *) tny_iterator_get_current (iter);
2446 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2447 has_uncached_messages = TRUE;
2448 g_object_unref (header);
2450 g_object_unref (iter);
2451 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2453 /* Get account and set it into mail_operation */
2454 if (tny_list_get_length (header_list) >= 1) {
2455 TnyIterator *iterator = tny_list_create_iterator (header_list);
2456 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2458 TnyFolder *folder = tny_header_get_folder (header);
2460 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2461 g_object_unref (folder);
2463 g_object_unref (header);
2465 g_object_unref (iterator);
2468 msg_list_size = compute_message_list_size (header_list);
2470 modest_mail_operation_notify_start (self);
2471 iter = tny_list_create_iterator (header_list);
2472 if (!tny_iterator_is_done (iter)) {
2473 /* notify about the start of the operation */
2474 ModestMailOperationState *state;
2475 state = modest_mail_operation_clone_state (self);
2478 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2481 GetMsgInfo *msg_info = NULL;
2482 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2483 TnyFolder *folder = tny_header_get_folder (header);
2485 /* Create the message info */
2486 msg_info = g_slice_new0 (GetMsgInfo);
2487 msg_info->mail_op = g_object_ref (self);
2488 msg_info->header = g_object_ref (header);
2489 msg_info->more_msgs = g_object_ref (iter);
2490 msg_info->user_callback = user_callback;
2491 msg_info->user_data = user_data;
2492 msg_info->destroy_notify = notify;
2493 msg_info->last_total_bytes = 0;
2494 msg_info->sum_total_bytes = 0;
2495 msg_info->total_bytes = msg_list_size;
2497 /* The callback will call it per each header */
2498 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2500 /* Free and go on */
2501 g_object_unref (header);
2502 g_object_unref (folder);
2503 g_slice_free (ModestMailOperationState, state);
2505 g_object_unref (iter);
2510 remove_msgs_async_cb (TnyFolder *folder,
2515 gboolean expunge, leave_on_server;
2516 const gchar *account_name;
2518 TnyAccount *account;
2519 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2520 ModestMailOperation *self;
2521 ModestMailOperationPrivate *priv;
2523 self = (ModestMailOperation *) user_data;
2524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2526 if (canceled || err) {
2527 /* If canceled by the user, ignore the error given by Tinymail */
2529 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2531 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2532 priv->error = g_error_copy ((const GError *) err);
2533 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2536 modest_mail_operation_notify_end (self);
2537 g_object_unref (self);
2541 account = tny_folder_get_account (folder);
2542 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2544 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2546 proto = tny_account_get_proto (account);
2547 g_object_unref (account);
2550 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2552 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2553 modest_tny_folder_is_remote_folder (folder) == FALSE)
2559 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2564 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2566 gboolean remove_to_trash /*ignored*/)
2568 TnyFolder *folder = NULL;
2569 ModestMailOperationPrivate *priv;
2570 TnyIterator *iter = NULL;
2571 TnyHeader *header = NULL;
2572 TnyList *remove_headers = NULL;
2573 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2575 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2576 g_return_if_fail (TNY_IS_LIST (headers));
2578 if (remove_to_trash)
2579 g_warning ("remove to trash is not implemented");
2581 if (tny_list_get_length(headers) == 0) {
2582 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2583 goto cleanup; /* nothing to do */
2586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2587 remove_headers = g_object_ref(headers);
2589 /* Get folder from first header and sync it */
2590 iter = tny_list_create_iterator (headers);
2591 header = TNY_HEADER (tny_iterator_get_current (iter));
2593 folder = tny_header_get_folder (header);
2594 if (!TNY_IS_FOLDER(folder)) {
2595 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2599 /* Don't remove messages that are being sent */
2600 if (modest_tny_folder_is_local_folder (folder)) {
2601 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2603 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2604 TnyTransportAccount *traccount = NULL;
2605 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2606 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2608 ModestTnySendQueueStatus status;
2609 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2610 TnyIterator *iter = tny_list_create_iterator(headers);
2611 g_object_unref(remove_headers);
2612 remove_headers = TNY_LIST(tny_simple_list_new());
2613 while (!tny_iterator_is_done(iter)) {
2615 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2616 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2617 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2618 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2619 tny_list_append(remove_headers, G_OBJECT(hdr));
2621 g_object_unref(hdr);
2623 tny_iterator_next(iter);
2625 g_object_unref(iter);
2626 g_object_unref(traccount);
2630 /* Get account and set it into mail_operation */
2631 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2632 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2633 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2635 /* remove message from folder */
2636 modest_mail_operation_notify_start (self);
2637 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2638 NULL, g_object_ref (self));
2642 g_object_unref (remove_headers);
2644 g_object_unref (header);
2646 g_object_unref (iter);
2648 g_object_unref (folder);
2652 notify_progress_of_multiple_messages (ModestMailOperation *self,
2654 gint *last_total_bytes,
2655 gint *sum_total_bytes,
2657 gboolean increment_done)
2659 ModestMailOperationPrivate *priv;
2660 ModestMailOperationState *state;
2661 gboolean is_num_bytes = FALSE;
2663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2665 /* We know that tinymail sends us information about
2666 * transferred bytes with this particular message
2668 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2669 * I just added the 'if' so we don't get runtime warning)
2671 if (status->message)
2672 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2674 state = modest_mail_operation_clone_state (self);
2675 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2676 /* We know that we're in a different message when the
2677 total number of bytes to transfer is different. Of
2678 course it could fail if we're transferring messages
2679 of the same size, but this is a workarround */
2680 if (status->of_total != *last_total_bytes) {
2681 /* We need to increment the done when there is
2682 no information about each individual
2683 message, we need to do this in message
2684 transfers, and we don't do it for getting
2688 *sum_total_bytes += *last_total_bytes;
2689 *last_total_bytes = status->of_total;
2691 state->bytes_done += status->position + *sum_total_bytes;
2692 state->bytes_total = total_bytes;
2694 /* Notify the status change. Only notify about changes
2695 referred to bytes */
2696 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2700 g_slice_free (ModestMailOperationState, state);
2704 transfer_msgs_status_cb (GObject *obj,
2708 XFerMsgsAsyncHelper *helper;
2710 g_return_if_fail (status != NULL);
2712 /* Show only the status information we want */
2713 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2716 helper = (XFerMsgsAsyncHelper *) user_data;
2717 g_return_if_fail (helper != NULL);
2719 /* Notify progress */
2720 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2721 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2726 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2728 XFerMsgsAsyncHelper *helper;
2729 ModestMailOperation *self;
2730 ModestMailOperationPrivate *priv;
2731 gboolean finished = TRUE;
2733 helper = (XFerMsgsAsyncHelper *) user_data;
2734 self = helper->mail_op;
2736 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2739 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2741 priv->error = g_error_copy (err);
2743 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2744 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2745 if (helper->more_msgs) {
2746 /* We'll transfer the next message in the list */
2747 tny_iterator_next (helper->more_msgs);
2748 if (!tny_iterator_is_done (helper->more_msgs)) {
2749 GObject *next_header;
2750 g_object_unref (helper->headers);
2751 helper->headers = tny_simple_list_new ();
2752 next_header = tny_iterator_get_current (helper->more_msgs);
2753 tny_list_append (helper->headers, next_header);
2754 g_object_unref (next_header);
2760 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2766 /* Update folder counts */
2767 tny_folder_poke_status (folder);
2768 tny_folder_poke_status (helper->dest_folder);
2770 /* Notify about operation end */
2771 modest_mail_operation_notify_end (self);
2773 /* If user defined callback function was defined, call it */
2774 if (helper->user_callback) {
2775 /* This is not a GDK lock because we are a Tinymail callback and
2776 * Tinymail already acquires the Gdk lock */
2778 /* no gdk_threads_enter (), CHECKED */
2779 helper->user_callback (self, helper->user_data);
2780 /* no gdk_threads_leave (), CHECKED */
2784 if (helper->more_msgs)
2785 g_object_unref (helper->more_msgs);
2786 if (helper->headers)
2787 g_object_unref (helper->headers);
2788 if (helper->dest_folder)
2789 g_object_unref (helper->dest_folder);
2790 if (helper->mail_op)
2791 g_object_unref (helper->mail_op);
2792 g_slice_free (XFerMsgsAsyncHelper, helper);
2794 /* Transfer more messages */
2795 tny_folder_transfer_msgs_async (folder,
2797 helper->dest_folder,
2800 transfer_msgs_status_cb,
2806 compute_message_list_size (TnyList *headers)
2811 iter = tny_list_create_iterator (headers);
2812 while (!tny_iterator_is_done (iter)) {
2813 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2814 size += tny_header_get_message_size (header);
2815 g_object_unref (header);
2816 tny_iterator_next (iter);
2818 g_object_unref (iter);
2824 compute_message_array_size (GPtrArray *headers)
2829 for (i = 0; i < headers->len; i++) {
2830 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2831 size += tny_header_get_message_size (header);
2839 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2842 gboolean delete_original,
2843 XferMsgsAsyncUserCallback user_callback,
2846 ModestMailOperationPrivate *priv = NULL;
2847 TnyIterator *iter = NULL;
2848 TnyFolder *src_folder = NULL;
2849 XFerMsgsAsyncHelper *helper = NULL;
2850 TnyHeader *header = NULL;
2851 ModestTnyFolderRules rules = 0;
2852 TnyAccount *dst_account = NULL;
2853 gboolean leave_on_server;
2855 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2856 g_return_if_fail (headers && TNY_IS_LIST (headers));
2857 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2860 priv->total = tny_list_get_length (headers);
2862 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2863 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2865 /* Apply folder rules */
2866 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2867 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2868 /* Set status failed and set an error */
2869 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2870 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2871 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2872 _CS("ckct_ib_unable_to_paste_here"));
2873 /* Notify the queue */
2874 modest_mail_operation_notify_end (self);
2878 /* Get source folder */
2879 iter = tny_list_create_iterator (headers);
2880 header = TNY_HEADER (tny_iterator_get_current (iter));
2882 src_folder = tny_header_get_folder (header);
2883 g_object_unref (header);
2885 g_object_unref (iter);
2887 if (src_folder == NULL) {
2888 /* Notify the queue */
2889 modest_mail_operation_notify_end (self);
2891 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2896 /* Check folder source and destination */
2897 if (src_folder == folder) {
2898 /* Set status failed and set an error */
2899 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2900 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2901 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2902 _("mail_in_ui_folder_copy_target_error"));
2904 /* Notify the queue */
2905 modest_mail_operation_notify_end (self);
2908 g_object_unref (src_folder);
2912 /* Create the helper */
2913 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2914 helper->mail_op = g_object_ref(self);
2915 helper->dest_folder = g_object_ref(folder);
2916 helper->user_callback = user_callback;
2917 helper->user_data = user_data;
2918 helper->last_total_bytes = 0;
2919 helper->sum_total_bytes = 0;
2920 helper->total_bytes = compute_message_list_size (headers);
2922 /* Get account and set it into mail_operation */
2923 priv->account = modest_tny_folder_get_account (src_folder);
2924 dst_account = modest_tny_folder_get_account (folder);
2926 if (priv->account == dst_account) {
2927 /* Transfer all messages at once using the fast
2928 * method. Note that depending on the server this
2929 * might not be that fast, and might not be
2930 * user-cancellable either */
2931 helper->headers = g_object_ref (headers);
2932 helper->more_msgs = NULL;
2934 /* Transfer messages one by one so the user can cancel
2937 helper->headers = tny_simple_list_new ();
2938 helper->more_msgs = tny_list_create_iterator (headers);
2939 hdr = tny_iterator_get_current (helper->more_msgs);
2940 tny_list_append (helper->headers, hdr);
2941 g_object_unref (hdr);
2944 /* If leave_on_server is set to TRUE then don't use
2945 delete_original, we always pass FALSE. This is because
2946 otherwise tinymail will try to sync the source folder and
2947 this could cause an error if we're offline while
2948 transferring an already downloaded message from a POP
2950 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2951 MODEST_PROTOCOL_STORE_POP) {
2952 const gchar *account_name;
2954 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2955 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2958 leave_on_server = FALSE;
2961 /* Do not delete messages if leave on server is TRUE */
2962 helper->delete = (leave_on_server) ? FALSE : delete_original;
2964 modest_mail_operation_notify_start (self);
2965 tny_folder_transfer_msgs_async (src_folder,
2970 transfer_msgs_status_cb,
2972 g_object_unref (src_folder);
2973 g_object_unref (dst_account);
2978 on_refresh_folder (TnyFolder *folder,
2983 RefreshAsyncHelper *helper = NULL;
2984 ModestMailOperation *self = NULL;
2985 ModestMailOperationPrivate *priv = NULL;
2987 helper = (RefreshAsyncHelper *) user_data;
2988 self = helper->mail_op;
2989 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2991 g_return_if_fail(priv!=NULL);
2994 priv->error = g_error_copy (error);
2995 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3000 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3001 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3002 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3003 _("Error trying to refresh the contents of %s"),
3004 tny_folder_get_name (folder));
3008 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3011 /* Call user defined callback, if it exists */
3012 if (helper->user_callback) {
3014 /* This is not a GDK lock because we are a Tinymail callback and
3015 * Tinymail already acquires the Gdk lock */
3016 helper->user_callback (self, folder, helper->user_data);
3020 g_slice_free (RefreshAsyncHelper, helper);
3022 /* Notify about operation end */
3023 modest_mail_operation_notify_end (self);
3024 g_object_unref(self);
3028 on_refresh_folder_status_update (GObject *obj,
3032 RefreshAsyncHelper *helper = NULL;
3033 ModestMailOperation *self = NULL;
3034 ModestMailOperationPrivate *priv = NULL;
3035 ModestMailOperationState *state;
3037 g_return_if_fail (user_data != NULL);
3038 g_return_if_fail (status != NULL);
3040 /* Show only the status information we want */
3041 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3044 helper = (RefreshAsyncHelper *) user_data;
3045 self = helper->mail_op;
3046 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3050 priv->done = status->position;
3051 priv->total = status->of_total;
3053 state = modest_mail_operation_clone_state (self);
3055 /* This is not a GDK lock because we are a Tinymail callback and
3056 * Tinymail already acquires the Gdk lock */
3057 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3059 g_slice_free (ModestMailOperationState, state);
3063 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3065 RefreshAsyncUserCallback user_callback,
3068 ModestMailOperationPrivate *priv = NULL;
3069 RefreshAsyncHelper *helper = NULL;
3071 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3073 /* Check memory low */
3074 if (_check_memory_low (self)) {
3076 user_callback (self, folder, user_data);
3077 /* Notify about operation end */
3078 modest_mail_operation_notify_end (self);
3082 /* Get account and set it into mail_operation */
3083 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3084 priv->account = modest_tny_folder_get_account (folder);
3085 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3087 /* Create the helper */
3088 helper = g_slice_new0 (RefreshAsyncHelper);
3089 helper->mail_op = g_object_ref(self);
3090 helper->user_callback = user_callback;
3091 helper->user_data = user_data;
3093 modest_mail_operation_notify_start (self);
3095 /* notify that the operation was started */
3096 ModestMailOperationState *state;
3097 state = modest_mail_operation_clone_state (self);
3100 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3103 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3105 tny_folder_refresh_async (folder,
3107 on_refresh_folder_status_update,
3112 run_queue_stop (ModestTnySendQueue *queue,
3113 ModestMailOperation *self)
3115 ModestMailOperationPrivate *priv;
3117 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3118 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3121 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3123 modest_mail_operation_notify_end (self);
3124 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3125 g_object_unref (self);
3128 modest_mail_operation_run_queue (ModestMailOperation *self,
3129 ModestTnySendQueue *queue)
3131 ModestMailOperationPrivate *priv;
3133 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3134 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3135 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3137 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3138 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3139 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3141 modest_mail_operation_notify_start (self);
3142 g_object_ref (self);
3143 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3147 sync_folder_finish_callback (TnyFolder *self,
3153 ModestMailOperation *mail_op;
3154 ModestMailOperationPrivate *priv;
3156 mail_op = (ModestMailOperation *) user_data;
3157 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3159 /* If canceled by the user, ignore the error given by Tinymail */
3161 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3163 /* If the operation was a sync then the status is
3164 failed, but if it's part of another operation then
3165 just set it as finished with errors */
3166 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3167 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3169 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3170 priv->error = g_error_copy ((const GError *) err);
3171 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3173 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3176 modest_mail_operation_notify_end (mail_op);
3177 g_object_unref (mail_op);
3181 modest_mail_operation_sync_folder (ModestMailOperation *self,
3182 TnyFolder *folder, gboolean expunge)
3184 ModestMailOperationPrivate *priv;
3186 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3187 g_return_if_fail (TNY_IS_FOLDER (folder));
3188 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3190 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3191 priv->account = modest_tny_folder_get_account (folder);
3192 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3194 modest_mail_operation_notify_start (self);
3195 g_object_ref (self);
3196 tny_folder_sync_async (folder, expunge,
3197 (TnyFolderCallback) sync_folder_finish_callback,
3202 modest_mail_operation_notify_start (ModestMailOperation *self)
3204 ModestMailOperationPrivate *priv = NULL;
3206 g_return_if_fail (self);
3208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3210 /* Ensure that all the fields are filled correctly */
3211 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3213 /* Notify the observers about the mail operation. We do not
3214 wrapp this emission because we assume that this function is
3215 always called from within the main lock */
3216 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3221 * It's used by the mail operation queue to notify the observers
3222 * attached to that signal that the operation finished. We need to use
3223 * that because tinymail does not give us the progress of a given
3224 * operation when it finishes (it directly calls the operation
3228 modest_mail_operation_notify_end (ModestMailOperation *self)
3230 ModestMailOperationPrivate *priv = NULL;
3232 g_return_if_fail (self);
3234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3236 /* Notify the observers about the mail operation end. We do
3237 not wrapp this emission because we assume that this
3238 function is always called from within the main lock */
3239 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3241 /* Remove the error user data */
3242 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3243 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3247 modest_mail_operation_get_account (ModestMailOperation *self)
3249 ModestMailOperationPrivate *priv = NULL;
3251 g_return_val_if_fail (self, NULL);
3253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3255 return (priv->account) ? g_object_ref (priv->account) : NULL;
3259 modest_mail_operation_noop (ModestMailOperation *self)
3261 ModestMailOperationPrivate *priv = NULL;
3263 g_return_if_fail (self);
3265 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3266 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3267 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3271 /* This mail operation does nothing actually */
3272 modest_mail_operation_notify_start (self);
3273 modest_mail_operation_notify_end (self);
3278 modest_mail_operation_to_string (ModestMailOperation *self)
3280 const gchar *type, *status, *account_id;
3281 ModestMailOperationPrivate *priv = NULL;
3283 g_return_val_if_fail (self, NULL);
3285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3287 /* new operations don't have anything interesting */
3288 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3289 return g_strdup_printf ("%p <new operation>", self);
3291 switch (priv->op_type) {
3292 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3293 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3294 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3295 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3296 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3297 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3298 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3299 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3300 default: type = "UNEXPECTED"; break;
3303 switch (priv->status) {
3304 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3305 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3306 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3307 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3308 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3309 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3310 default: status= "UNEXPECTED"; break;
3313 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3315 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3316 priv->done, priv->total,
3317 priv->error && priv->error->message ? priv->error->message : "");
3321 * Once the mail operations were objects this will be no longer
3322 * needed. I don't like it, but we need it for the moment
3325 _check_memory_low (ModestMailOperation *mail_op)
3327 if (modest_platform_check_memory_low (NULL, FALSE)) {
3328 ModestMailOperationPrivate *priv;
3330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3331 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3332 g_set_error (&(priv->error),
3333 MODEST_MAIL_OPERATION_ERROR,
3334 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3335 "Not enough memory to complete the operation");