1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers);
100 static guint compute_message_array_size (GPtrArray *headers);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 static gboolean _check_memory_low (ModestMailOperation *mail_op);
112 enum _ModestMailOperationSignals
114 PROGRESS_CHANGED_SIGNAL,
115 OPERATION_STARTED_SIGNAL,
116 OPERATION_FINISHED_SIGNAL,
120 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
121 struct _ModestMailOperationPrivate {
127 ErrorCheckingUserCallback error_checking;
128 gpointer error_checking_user_data;
129 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
130 ModestMailOperationStatus status;
131 ModestMailOperationTypeOperation op_type;
134 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
135 MODEST_TYPE_MAIL_OPERATION, \
136 ModestMailOperationPrivate))
138 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
139 priv->status = new_status;\
144 GetMsgAsyncUserCallback user_callback;
146 TnyIterator *more_msgs;
148 ModestMailOperation *mail_op;
149 GDestroyNotify destroy_notify;
150 gint last_total_bytes;
151 gint sum_total_bytes;
155 typedef struct _RefreshAsyncHelper {
156 ModestMailOperation *mail_op;
157 RefreshAsyncUserCallback user_callback;
159 } RefreshAsyncHelper;
161 typedef struct _XFerMsgsAsyncHelper
163 ModestMailOperation *mail_op;
165 TnyIterator *more_msgs;
166 TnyFolder *dest_folder;
167 XferMsgsAsyncUserCallback user_callback;
170 gint last_total_bytes;
171 gint sum_total_bytes;
173 } XFerMsgsAsyncHelper;
175 typedef struct _XFerFolderAsyncHelper
177 ModestMailOperation *mail_op;
178 XferFolderAsyncUserCallback user_callback;
180 } XFerFolderAsyncHelper;
182 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
186 static void modest_mail_operation_create_msg (ModestMailOperation *self,
187 const gchar *from, const gchar *to,
188 const gchar *cc, const gchar *bcc,
189 const gchar *subject, const gchar *plain_body,
190 const gchar *html_body, const GList *attachments_list,
191 const GList *images_list,
192 TnyHeaderFlags priority_flags,
193 ModestMailOperationCreateMsgCallback callback,
196 static gboolean idle_notify_queue (gpointer data);
199 ModestMailOperation *mail_op;
207 GList *attachments_list;
209 TnyHeaderFlags priority_flags;
210 ModestMailOperationCreateMsgCallback callback;
216 ModestMailOperation *mail_op;
218 ModestMailOperationCreateMsgCallback callback;
223 static GObjectClass *parent_class = NULL;
225 static guint signals[NUM_SIGNALS] = {0};
228 modest_mail_operation_get_type (void)
230 static GType my_type = 0;
232 static const GTypeInfo my_info = {
233 sizeof(ModestMailOperationClass),
234 NULL, /* base init */
235 NULL, /* base finalize */
236 (GClassInitFunc) modest_mail_operation_class_init,
237 NULL, /* class finalize */
238 NULL, /* class data */
239 sizeof(ModestMailOperation),
241 (GInstanceInitFunc) modest_mail_operation_init,
244 my_type = g_type_register_static (G_TYPE_OBJECT,
245 "ModestMailOperation",
252 modest_mail_operation_class_init (ModestMailOperationClass *klass)
254 GObjectClass *gobject_class;
255 gobject_class = (GObjectClass*) klass;
257 parent_class = g_type_class_peek_parent (klass);
258 gobject_class->finalize = modest_mail_operation_finalize;
260 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
263 * ModestMailOperation::progress-changed
264 * @self: the #MailOperation that emits the signal
265 * @user_data: user data set when the signal handler was connected
267 * Emitted when the progress of a mail operation changes
269 signals[PROGRESS_CHANGED_SIGNAL] =
270 g_signal_new ("progress-changed",
271 G_TYPE_FROM_CLASS (gobject_class),
273 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
275 g_cclosure_marshal_VOID__POINTER,
276 G_TYPE_NONE, 1, G_TYPE_POINTER);
280 * This signal is issued whenever a mail operation starts, and
281 * starts mean when the tinymail operation is issued. This
282 * means that it could happen that something wrong happens and
283 * the tinymail function is never called. In this situation a
284 * operation-finished will be issued without any
287 signals[OPERATION_STARTED_SIGNAL] =
288 g_signal_new ("operation-started",
289 G_TYPE_FROM_CLASS (gobject_class),
291 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
293 g_cclosure_marshal_VOID__VOID,
298 * This signal is issued whenever a mail operation
299 * finishes. Note that this signal could be issued without any
300 * previous "operation-started" signal, because this last one
301 * is only issued when the tinymail operation is successfully
304 signals[OPERATION_FINISHED_SIGNAL] =
305 g_signal_new ("operation-finished",
306 G_TYPE_FROM_CLASS (gobject_class),
308 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
310 g_cclosure_marshal_VOID__VOID,
315 modest_mail_operation_init (ModestMailOperation *obj)
317 ModestMailOperationPrivate *priv;
319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
321 priv->account = NULL;
322 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
323 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
328 priv->error_checking = NULL;
329 priv->error_checking_user_data = NULL;
333 modest_mail_operation_finalize (GObject *obj)
335 ModestMailOperationPrivate *priv;
337 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
342 g_error_free (priv->error);
346 g_object_unref (priv->source);
350 g_object_unref (priv->account);
351 priv->account = NULL;
355 G_OBJECT_CLASS(parent_class)->finalize (obj);
359 modest_mail_operation_new (GObject *source)
361 ModestMailOperation *obj;
362 ModestMailOperationPrivate *priv;
364 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
368 priv->source = g_object_ref(source);
374 modest_mail_operation_new_with_error_handling (GObject *source,
375 ErrorCheckingUserCallback error_handler,
377 ErrorCheckingUserDataDestroyer error_handler_destroyer)
379 ModestMailOperation *obj;
380 ModestMailOperationPrivate *priv;
382 obj = modest_mail_operation_new (source);
383 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
385 g_return_val_if_fail (error_handler != NULL, obj);
386 priv->error_checking = error_handler;
387 priv->error_checking_user_data = user_data;
388 priv->error_checking_user_data_destroyer = error_handler_destroyer;
394 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
396 ModestMailOperationPrivate *priv;
398 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
401 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
403 /* Call the user callback */
404 if (priv->error_checking != NULL)
405 priv->error_checking (self, priv->error_checking_user_data);
409 ModestMailOperationTypeOperation
410 modest_mail_operation_get_type_operation (ModestMailOperation *self)
412 ModestMailOperationPrivate *priv;
414 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
415 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
419 return priv->op_type;
423 modest_mail_operation_is_mine (ModestMailOperation *self,
426 ModestMailOperationPrivate *priv;
428 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
432 if (priv->source == NULL) return FALSE;
434 return priv->source == me;
438 modest_mail_operation_get_source (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
445 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
447 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
451 return (priv->source) ? g_object_ref (priv->source) : NULL;
454 ModestMailOperationStatus
455 modest_mail_operation_get_status (ModestMailOperation *self)
457 ModestMailOperationPrivate *priv;
459 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
460 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
461 MODEST_MAIL_OPERATION_STATUS_INVALID);
463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
465 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
466 return MODEST_MAIL_OPERATION_STATUS_INVALID;
473 modest_mail_operation_get_error (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (self, NULL);
478 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
483 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
491 modest_mail_operation_cancel (ModestMailOperation *self)
493 ModestMailOperationPrivate *priv;
494 gboolean canceled = FALSE;
496 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
501 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
503 /* Cancel the mail operation */
504 g_return_val_if_fail (priv->account, FALSE);
505 tny_account_cancel (priv->account);
507 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
508 ModestTnySendQueue *queue;
509 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
512 /* Cancel the sending of the following next messages */
513 if (TNY_IS_SEND_QUEUE (queue))
514 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
521 modest_mail_operation_get_task_done (ModestMailOperation *self)
523 ModestMailOperationPrivate *priv;
525 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
533 modest_mail_operation_get_task_total (ModestMailOperation *self)
535 ModestMailOperationPrivate *priv;
537 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 modest_mail_operation_is_finished (ModestMailOperation *self)
547 ModestMailOperationPrivate *priv;
548 gboolean retval = FALSE;
550 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
553 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
555 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
556 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
557 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
558 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
568 * Creates an image of the current state of a mail operation, the
569 * caller must free it
571 static ModestMailOperationState *
572 modest_mail_operation_clone_state (ModestMailOperation *self)
574 ModestMailOperationState *state;
575 ModestMailOperationPrivate *priv;
577 /* FIXME: this should be fixed properly
579 * in some cases, priv was NULL, so checking here to
582 g_return_val_if_fail (self, NULL);
583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
584 g_return_val_if_fail (priv, NULL);
589 state = g_slice_new (ModestMailOperationState);
591 state->status = priv->status;
592 state->op_type = priv->op_type;
593 state->done = priv->done;
594 state->total = priv->total;
595 state->finished = modest_mail_operation_is_finished (self);
596 state->bytes_done = 0;
597 state->bytes_total = 0;
602 /* ******************************************************************* */
603 /* ************************** SEND ACTIONS ************************* */
604 /* ******************************************************************* */
607 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
613 ModestMailOperationPrivate *priv;
614 ModestMailOperation *self;
616 self = MODEST_MAIL_OPERATION (user_data);
617 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
619 if (cancelled || err)
623 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
624 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
625 "Error adding a msg to the send queue\n");
626 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
628 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
631 modest_mail_operation_notify_end (self);
632 g_object_unref (self);
636 modest_mail_operation_send_mail (ModestMailOperation *self,
637 TnyTransportAccount *transport_account,
640 TnySendQueue *send_queue = NULL;
641 ModestMailOperationPrivate *priv;
643 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
644 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
645 g_return_if_fail (msg && TNY_IS_MSG (msg));
647 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
649 /* Get account and set it into mail_operation */
650 priv->account = g_object_ref (transport_account);
651 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
655 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
656 if (!TNY_IS_SEND_QUEUE(send_queue)) {
658 g_error_free (priv->error);
661 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
662 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
663 "modest: could not find send queue for account\n");
664 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
665 modest_mail_operation_notify_end (self);
667 modest_mail_operation_notify_start (self);
668 /* Add the msg to the queue. The callback will
669 finalize the mail operation */
670 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
671 NULL, g_object_ref (self));
672 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
679 idle_create_msg_cb (gpointer idle_data)
681 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
683 /* This is a GDK lock because we are an idle callback and
684 * info->callback can contain Gtk+ code */
686 gdk_threads_enter (); /* CHECKED */
687 info->callback (info->mail_op, info->msg, info->userdata);
689 g_object_unref (info->mail_op);
691 g_object_unref (info->msg);
692 g_slice_free (CreateMsgIdleInfo, info);
693 gdk_threads_leave (); /* CHECKED */
699 create_msg_thread (gpointer thread_data)
701 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
702 TnyMsg *new_msg = NULL;
703 ModestMailOperationPrivate *priv;
705 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
706 if (info->html_body == NULL) {
707 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
708 info->bcc, info->subject, info->plain_body,
709 info->attachments_list,
712 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
713 info->bcc, info->subject, info->html_body,
714 info->plain_body, info->attachments_list,
722 /* Set priority flags in message */
723 header = tny_msg_get_header (new_msg);
724 tny_header_set_flag (header, info->priority_flags);
726 /* Set attachment flags in message */
727 if (info->attachments_list != NULL)
728 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
730 g_object_unref (G_OBJECT(header));
732 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
734 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
735 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
736 "modest: failed to create a new msg\n");
744 g_free (info->plain_body);
745 g_free (info->html_body);
746 g_free (info->subject);
747 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
748 g_list_free (info->attachments_list);
749 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
750 g_list_free (info->images_list);
752 if (info->callback) {
753 CreateMsgIdleInfo *idle_info;
754 idle_info = g_slice_new0 (CreateMsgIdleInfo);
755 idle_info->mail_op = g_object_ref (info->mail_op);
756 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
757 idle_info->callback = info->callback;
758 idle_info->userdata = info->userdata;
759 g_idle_add (idle_create_msg_cb, idle_info);
761 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
764 g_object_unref (info->mail_op);
765 g_slice_free (CreateMsgInfo, info);
766 if (new_msg) g_object_unref(new_msg);
772 modest_mail_operation_create_msg (ModestMailOperation *self,
773 const gchar *from, const gchar *to,
774 const gchar *cc, const gchar *bcc,
775 const gchar *subject, const gchar *plain_body,
776 const gchar *html_body,
777 const GList *attachments_list,
778 const GList *images_list,
779 TnyHeaderFlags priority_flags,
780 ModestMailOperationCreateMsgCallback callback,
783 CreateMsgInfo *info = NULL;
785 info = g_slice_new0 (CreateMsgInfo);
786 info->mail_op = g_object_ref (self);
788 info->from = g_strdup (from);
789 info->to = g_strdup (to);
790 info->cc = g_strdup (cc);
791 info->bcc = g_strdup (bcc);
792 info->subject = g_strdup (subject);
793 info->plain_body = g_strdup (plain_body);
794 info->html_body = g_strdup (html_body);
795 info->attachments_list = g_list_copy ((GList *) attachments_list);
796 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
797 info->images_list = g_list_copy ((GList *) images_list);
798 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
799 info->priority_flags = priority_flags;
801 info->callback = callback;
802 info->userdata = userdata;
804 g_thread_create (create_msg_thread, info, FALSE, NULL);
809 TnyTransportAccount *transport_account;
814 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
818 ModestMailOperationPrivate *priv = NULL;
819 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
820 TnyFolder *draft_folder = NULL;
821 TnyFolder *outbox_folder = NULL;
822 TnyHeader *header = NULL;
824 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
827 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
828 modest_mail_operation_notify_end (self);
832 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
833 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
834 modest_mail_operation_notify_end (self);
838 /* Call mail operation */
839 modest_mail_operation_send_mail (self, info->transport_account, msg);
841 if (info->draft_msg != NULL) {
842 TnyList *tmp_headers = NULL;
843 TnyFolder *folder = NULL;
844 TnyFolder *src_folder = NULL;
845 TnyFolderType folder_type;
846 TnyTransportAccount *transport_account = NULL;
848 /* To remove the old mail from its source folder, we need to get the
849 * transport account of the original draft message (the transport account
850 * might have been changed by the user) */
851 header = tny_msg_get_header (info->draft_msg);
852 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
853 modest_runtime_get_account_store(), header);
854 if (transport_account == NULL)
855 transport_account = g_object_ref(info->transport_account);
856 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
857 TNY_FOLDER_TYPE_DRAFTS);
858 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
859 TNY_FOLDER_TYPE_OUTBOX);
860 g_object_unref(transport_account);
863 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
867 if (!outbox_folder) {
868 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
873 folder = tny_msg_get_folder (info->draft_msg);
874 if (folder == NULL) goto end;
875 folder_type = modest_tny_folder_guess_folder_type (folder);
877 if (folder_type == TNY_FOLDER_TYPE_INVALID)
878 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
880 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
881 src_folder = outbox_folder;
883 src_folder = draft_folder;
885 /* Note: This can fail (with a warning) if the message is not really already in a folder,
886 * because this function requires it to have a UID. */
887 tmp_headers = tny_simple_list_new ();
888 tny_list_append (tmp_headers, (GObject*) header);
889 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
890 g_object_unref (tmp_headers);
891 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
893 g_object_unref (folder);
898 g_object_unref (header);
900 g_object_unref (info->draft_msg);
902 g_object_unref (draft_folder);
904 g_object_unref (outbox_folder);
905 if (info->transport_account)
906 g_object_unref (info->transport_account);
907 g_slice_free (SendNewMailInfo, info);
911 modest_mail_operation_send_new_mail (ModestMailOperation *self,
912 TnyTransportAccount *transport_account,
914 const gchar *from, const gchar *to,
915 const gchar *cc, const gchar *bcc,
916 const gchar *subject, const gchar *plain_body,
917 const gchar *html_body,
918 const GList *attachments_list,
919 const GList *images_list,
920 TnyHeaderFlags priority_flags)
922 ModestMailOperationPrivate *priv = NULL;
923 SendNewMailInfo *info;
925 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
926 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
928 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
929 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
930 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
931 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
933 /* Check parametters */
935 /* Set status failed and set an error */
936 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
937 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
938 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
939 _("Error trying to send a mail. You need to set at least one recipient"));
942 info = g_slice_new0 (SendNewMailInfo);
943 info->transport_account = transport_account;
944 if (transport_account)
945 g_object_ref (transport_account);
946 info->draft_msg = draft_msg;
948 g_object_ref (draft_msg);
951 modest_mail_operation_notify_start (self);
952 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
953 attachments_list, images_list, priority_flags,
954 modest_mail_operation_send_new_mail_cb, info);
960 TnyTransportAccount *transport_account;
962 SaveToDraftstCallback callback;
966 ModestMailOperation *mailop;
967 } SaveToDraftsAddMsgInfo;
970 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
975 ModestMailOperationPrivate *priv = NULL;
976 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
977 GError *io_error = NULL;
979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
981 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
982 io_error = priv->error;
986 g_warning ("%s: priv->error != NULL", __FUNCTION__);
987 g_error_free(priv->error);
990 priv->error = (err == NULL) ? NULL : g_error_copy(err);
992 if ((!priv->error) && (info->draft_msg != NULL)) {
993 TnyHeader *header = tny_msg_get_header (info->draft_msg);
994 TnyFolder *src_folder = tny_header_get_folder (header);
996 /* Remove the old draft */
997 tny_folder_remove_msg (src_folder, header, NULL);
999 /* Synchronize to expunge and to update the msg counts */
1000 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1001 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1003 g_object_unref (G_OBJECT(header));
1004 g_object_unref (G_OBJECT(src_folder));
1008 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1010 g_error_free (io_error);
1013 } else if (io_error) {
1014 priv->error = io_error;
1015 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1017 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1020 /* Call the user callback */
1022 info->callback (info->mailop, info->msg, info->user_data);
1024 if (info->transport_account)
1025 g_object_unref (G_OBJECT(info->transport_account));
1026 if (info->draft_msg)
1027 g_object_unref (G_OBJECT (info->draft_msg));
1029 g_object_unref (G_OBJECT(info->drafts));
1031 g_object_unref (G_OBJECT (info->msg));
1033 modest_mail_operation_notify_end (info->mailop);
1034 g_object_unref(info->mailop);
1035 g_slice_free (SaveToDraftsAddMsgInfo, info);
1040 TnyTransportAccount *transport_account;
1042 SaveToDraftstCallback callback;
1047 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1051 TnyFolder *drafts = NULL;
1052 ModestMailOperationPrivate *priv = NULL;
1053 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1055 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1058 if (!(priv->error)) {
1059 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1060 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1061 "modest: failed to create a new msg\n");
1064 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1065 TNY_FOLDER_TYPE_DRAFTS);
1066 if (!drafts && !(priv->error)) {
1067 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1068 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1069 "modest: failed to create a new msg\n");
1073 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1074 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1075 cb_info->transport_account = g_object_ref(info->transport_account);
1076 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1077 cb_info->callback = info->callback;
1078 cb_info->user_data = info->user_data;
1079 cb_info->drafts = g_object_ref(drafts);
1080 cb_info->msg = g_object_ref(msg);
1081 cb_info->mailop = g_object_ref(self);
1082 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1085 /* Call the user callback */
1086 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1088 info->callback (self, msg, info->user_data);
1089 modest_mail_operation_notify_end (self);
1093 g_object_unref (G_OBJECT(drafts));
1094 if (info->draft_msg)
1095 g_object_unref (G_OBJECT (info->draft_msg));
1096 if (info->transport_account)
1097 g_object_unref (G_OBJECT(info->transport_account));
1098 g_slice_free (SaveToDraftsInfo, info);
1102 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1103 TnyTransportAccount *transport_account,
1105 const gchar *from, const gchar *to,
1106 const gchar *cc, const gchar *bcc,
1107 const gchar *subject, const gchar *plain_body,
1108 const gchar *html_body,
1109 const GList *attachments_list,
1110 const GList *images_list,
1111 TnyHeaderFlags priority_flags,
1112 SaveToDraftstCallback callback,
1115 ModestMailOperationPrivate *priv = NULL;
1116 SaveToDraftsInfo *info = NULL;
1118 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1119 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1121 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1123 /* Get account and set it into mail_operation */
1124 priv->account = g_object_ref (transport_account);
1125 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1127 info = g_slice_new0 (SaveToDraftsInfo);
1128 info->transport_account = g_object_ref (transport_account);
1129 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1130 info->callback = callback;
1131 info->user_data = user_data;
1133 modest_mail_operation_notify_start (self);
1134 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1135 attachments_list, images_list, priority_flags,
1136 modest_mail_operation_save_to_drafts_cb, info);
1141 ModestMailOperation *mail_op;
1142 TnyMimePart *mime_part;
1144 GetMimePartSizeCallback callback;
1146 } GetMimePartSizeInfo;
1148 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1149 /* We use this folder observer to track the headers that have been
1150 * added to a folder */
1153 TnyList *new_headers;
1154 } InternalFolderObserver;
1157 GObjectClass parent;
1158 } InternalFolderObserverClass;
1160 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1162 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1163 internal_folder_observer,
1165 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1169 foreach_add_item (gpointer header, gpointer user_data)
1171 tny_list_prepend (TNY_LIST (user_data),
1172 g_object_ref (G_OBJECT (header)));
1175 /* This is the method that looks for new messages in a folder */
1177 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1179 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1181 TnyFolderChangeChanged changed;
1183 changed = tny_folder_change_get_changed (change);
1185 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1188 /* Get added headers */
1189 list = tny_simple_list_new ();
1190 tny_folder_change_get_added_headers (change, list);
1192 /* Add them to the folder observer */
1193 tny_list_foreach (list, foreach_add_item,
1194 derived->new_headers);
1196 g_object_unref (G_OBJECT (list));
1201 internal_folder_observer_init (InternalFolderObserver *self)
1203 self->new_headers = tny_simple_list_new ();
1206 internal_folder_observer_finalize (GObject *object)
1208 InternalFolderObserver *self;
1210 self = (InternalFolderObserver *) object;
1211 g_object_unref (self->new_headers);
1213 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1216 tny_folder_observer_init (TnyFolderObserverIface *iface)
1218 iface->update = internal_folder_observer_update;
1221 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1223 GObjectClass *object_class;
1225 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1226 object_class = (GObjectClass*) klass;
1227 object_class->finalize = internal_folder_observer_finalize;
1232 ModestMailOperation *mail_op;
1233 gchar *account_name;
1234 UpdateAccountCallback callback;
1239 TnyFolderObserver *inbox_observer;
1240 RetrieveAllCallback retrieve_all_cb;
1241 gboolean interactive;
1242 } UpdateAccountInfo;
1246 destroy_update_account_info (UpdateAccountInfo *info)
1248 g_free (info->account_name);
1249 g_object_unref (info->folders);
1250 g_object_unref (info->mail_op);
1251 g_slice_free (UpdateAccountInfo, info);
1255 update_account_get_msg_async_cb (TnyFolder *folder,
1261 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1263 /* Just delete the helper. Don't do anything with the new
1264 msg. There is also no need to check for errors */
1265 g_object_unref (msg_info->mail_op);
1266 g_object_unref (msg_info->header);
1267 g_slice_free (GetMsgInfo, msg_info);
1271 update_account_notify_user_and_free (UpdateAccountInfo *info,
1272 TnyList *new_headers)
1274 /* Set the account back to not busy */
1275 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1276 info->account_name, FALSE);
1280 info->callback (info->mail_op, new_headers, info->user_data);
1282 /* Mail operation end */
1283 modest_mail_operation_notify_end (info->mail_op);
1287 g_object_unref (new_headers);
1288 destroy_update_account_info (info);
1292 inbox_refreshed_cb (TnyFolder *inbox,
1297 UpdateAccountInfo *info;
1298 ModestMailOperationPrivate *priv;
1299 TnyIterator *new_headers_iter;
1300 GPtrArray *new_headers_array = NULL;
1301 gint max_size, retrieve_limit, i;
1302 ModestAccountMgr *mgr;
1303 ModestAccountRetrieveType retrieve_type;
1304 TnyList *new_headers = NULL;
1305 gboolean headers_only, ignore_limit;
1306 TnyTransportAccount *transport_account = NULL;
1308 info = (UpdateAccountInfo *) user_data;
1309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1310 mgr = modest_runtime_get_account_mgr ();
1312 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1313 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1315 if (canceled || err) {
1316 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1318 priv->error = g_error_copy (err);
1320 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1321 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1324 /* Notify the user about the error and then exit */
1325 update_account_notify_user_and_free (info, NULL);
1330 /* Try to send anyway */
1334 /* Get the message max size */
1335 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1336 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1338 max_size = G_MAXINT;
1340 max_size = max_size * KB;
1342 /* Create the new headers array. We need it to sort the
1343 new headers by date */
1344 new_headers_array = g_ptr_array_new ();
1345 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1346 while (!tny_iterator_is_done (new_headers_iter)) {
1347 TnyHeader *header = NULL;
1349 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1350 /* Apply per-message size limits */
1351 if (tny_header_get_message_size (header) < max_size)
1352 g_ptr_array_add (new_headers_array, g_object_ref (header));
1354 g_object_unref (header);
1355 tny_iterator_next (new_headers_iter);
1357 g_object_unref (new_headers_iter);
1358 tny_folder_remove_observer (inbox, info->inbox_observer);
1359 g_object_unref (info->inbox_observer);
1360 info->inbox_observer = NULL;
1362 if (new_headers_array->len == 0)
1365 /* Get per-account message amount retrieval limit */
1366 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1367 if (retrieve_limit == 0)
1368 retrieve_limit = G_MAXINT;
1370 /* Get per-account retrieval type */
1371 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1372 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1375 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1377 /* Ask the users if they want to retrieve all the messages
1378 even though the limit was exceeded */
1379 ignore_limit = FALSE;
1380 if (new_headers_array->len > retrieve_limit) {
1381 /* Ask the user if a callback has been specified and
1382 if the mail operation has a source (this means that
1383 was invoked by the user and not automatically by a
1385 if (info->retrieve_all_cb && priv->source)
1386 ignore_limit = info->retrieve_all_cb (priv->source,
1387 new_headers_array->len,
1391 if (!headers_only) {
1393 const gint msg_list_size = compute_message_array_size (new_headers_array);
1397 priv->total = new_headers_array->len;
1399 priv->total = MIN (new_headers_array->len, retrieve_limit);
1400 while (msg_num < priv->total) {
1401 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1402 TnyFolder *folder = tny_header_get_folder (header);
1403 GetMsgInfo *msg_info;
1405 /* Create the message info */
1406 msg_info = g_slice_new0 (GetMsgInfo);
1407 msg_info->mail_op = g_object_ref (info->mail_op);
1408 msg_info->header = g_object_ref (header);
1409 msg_info->total_bytes = msg_list_size;
1411 /* Get message in an async way */
1412 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1413 get_msg_status_cb, msg_info);
1415 g_object_unref (folder);
1421 /* Copy the headers to a list and free the array */
1422 new_headers = tny_simple_list_new ();
1423 for (i=0; i < new_headers_array->len; i++) {
1424 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1425 tny_list_append (new_headers, G_OBJECT (header));
1427 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1428 g_ptr_array_free (new_headers_array, FALSE);
1431 /* Get the transport account */
1432 transport_account = (TnyTransportAccount *)
1433 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1434 info->account_name);
1436 if (transport_account) {
1437 ModestTnySendQueue *send_queue;
1441 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1442 g_object_unref (transport_account);
1444 if (TNY_IS_SEND_QUEUE (send_queue)) {
1445 /* Get outbox folder */
1446 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1447 if (outbox) { /* this could fail in some cases */
1448 num_messages = tny_folder_get_all_count (outbox);
1449 g_object_unref (outbox);
1451 g_warning ("%s: could not get outbox", __FUNCTION__);
1455 if (num_messages != 0) {
1456 /* Reenable suspended items */
1457 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1460 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1461 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1467 /* Check if the operation was a success */
1469 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1471 /* Call the user callback and free */
1472 update_account_notify_user_and_free (info, new_headers);
1476 inbox_refresh_status_update (GObject *obj,
1480 UpdateAccountInfo *info = NULL;
1481 ModestMailOperation *self = NULL;
1482 ModestMailOperationPrivate *priv = NULL;
1483 ModestMailOperationState *state;
1485 g_return_if_fail (user_data != NULL);
1486 g_return_if_fail (status != NULL);
1488 /* Show only the status information we want */
1489 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1492 info = (UpdateAccountInfo *) user_data;
1493 self = info->mail_op;
1494 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1498 priv->done = status->position;
1499 priv->total = status->of_total;
1501 state = modest_mail_operation_clone_state (self);
1503 /* This is not a GDK lock because we are a Tinymail callback and
1504 * Tinymail already acquires the Gdk lock */
1505 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1507 g_slice_free (ModestMailOperationState, state);
1511 recurse_folders_async_cb (TnyFolderStore *folder_store,
1517 UpdateAccountInfo *info;
1518 ModestMailOperationPrivate *priv;
1520 info = (UpdateAccountInfo *) user_data;
1521 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1523 if (err || canceled) {
1524 /* If the error was previosly set by another callback
1525 don't set it again */
1527 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1529 priv->error = g_error_copy (err);
1531 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1532 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1536 /* We're not getting INBOX children if we don't want to poke all */
1537 TnyIterator *iter = tny_list_create_iterator (list);
1538 while (!tny_iterator_is_done (iter)) {
1539 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1541 /* Add to the list of all folders */
1542 tny_list_append (info->folders, (GObject *) folder);
1544 if (info->poke_all) {
1545 TnyList *folders = tny_simple_list_new ();
1546 /* Add pending call */
1547 info->pending_calls++;
1549 tny_folder_store_get_folders_async (folder, folders, NULL,
1550 recurse_folders_async_cb,
1552 g_object_unref (folders);
1555 g_object_unref (G_OBJECT (folder));
1557 tny_iterator_next (iter);
1559 g_object_unref (G_OBJECT (iter));
1562 /* Remove my own pending call */
1563 info->pending_calls--;
1565 /* This means that we have all the folders */
1566 if (info->pending_calls == 0) {
1567 TnyIterator *iter_all_folders;
1568 TnyFolder *inbox = NULL;
1570 /* If there was any error do not continue */
1572 update_account_notify_user_and_free (info, NULL);
1576 iter_all_folders = tny_list_create_iterator (info->folders);
1578 /* Do a poke status over all folders */
1579 while (!tny_iterator_is_done (iter_all_folders) &&
1580 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1581 TnyFolder *folder = NULL;
1583 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1585 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1586 /* Get a reference to the INBOX */
1587 inbox = g_object_ref (folder);
1589 /* Issue a poke status over the folder */
1591 tny_folder_poke_status (folder);
1594 /* Free and go to next */
1595 g_object_unref (folder);
1596 tny_iterator_next (iter_all_folders);
1598 g_object_unref (iter_all_folders);
1600 /* Refresh the INBOX */
1602 /* Refresh the folder. Our observer receives
1603 * the new emails during folder refreshes, so
1604 * we can use observer->new_headers
1606 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1607 tny_folder_add_observer (inbox, info->inbox_observer);
1609 /* Refresh the INBOX */
1610 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1611 g_object_unref (inbox);
1613 /* We could not perform the inbox refresh but
1614 we'll try to send mails anyway */
1615 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1621 modest_mail_operation_update_account (ModestMailOperation *self,
1622 const gchar *account_name,
1624 gboolean interactive,
1625 RetrieveAllCallback retrieve_all_cb,
1626 UpdateAccountCallback callback,
1629 UpdateAccountInfo *info = NULL;
1630 ModestMailOperationPrivate *priv = NULL;
1631 ModestTnyAccountStore *account_store = NULL;
1633 ModestMailOperationState *state;
1635 /* Init mail operation */
1636 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1639 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1640 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1642 /* Get the store account */
1643 account_store = modest_runtime_get_account_store ();
1645 modest_tny_account_store_get_server_account (account_store,
1647 TNY_ACCOUNT_TYPE_STORE);
1649 /* The above function could return NULL */
1650 if (!priv->account) {
1651 /* Check if the operation was a success */
1652 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1653 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1655 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1657 /* Call the user callback */
1659 callback (self, NULL, user_data);
1661 /* Notify about operation end */
1662 modest_mail_operation_notify_end (self);
1667 /* We have once seen priv->account getting finalized during this code,
1668 * therefore adding a reference (bug #82296) */
1670 g_object_ref (priv->account);
1672 /* Create the helper object */
1673 info = g_slice_new0 (UpdateAccountInfo);
1674 info->pending_calls = 1;
1675 info->folders = tny_simple_list_new ();
1676 info->mail_op = g_object_ref (self);
1677 info->poke_all = poke_all;
1678 info->interactive = interactive;
1679 info->account_name = g_strdup (account_name);
1680 info->callback = callback;
1681 info->user_data = user_data;
1682 info->retrieve_all_cb = retrieve_all_cb;
1684 /* Set account busy */
1685 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1686 modest_mail_operation_notify_start (self);
1688 /* notify about the start of the operation */
1689 state = modest_mail_operation_clone_state (self);
1693 /* Start notifying progress */
1694 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1695 g_slice_free (ModestMailOperationState, state);
1697 /* Get all folders and continue in the callback */
1698 folders = tny_simple_list_new ();
1699 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1701 recurse_folders_async_cb,
1703 g_object_unref (folders);
1705 g_object_unref (priv->account);
1710 * Used to notify the queue from the main
1711 * loop. We call it inside an idle call to achieve that
1714 idle_notify_queue (gpointer data)
1716 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1718 gdk_threads_enter ();
1719 modest_mail_operation_notify_end (mail_op);
1720 gdk_threads_leave ();
1721 g_object_unref (mail_op);
1727 compare_headers_by_date (gconstpointer a,
1730 TnyHeader **header1, **header2;
1731 time_t sent1, sent2;
1733 header1 = (TnyHeader **) a;
1734 header2 = (TnyHeader **) b;
1736 sent1 = tny_header_get_date_sent (*header1);
1737 sent2 = tny_header_get_date_sent (*header2);
1739 /* We want the most recent ones (greater time_t) at the
1748 /* ******************************************************************* */
1749 /* ************************** STORE ACTIONS ************************* */
1750 /* ******************************************************************* */
1753 ModestMailOperation *mail_op;
1754 CreateFolderUserCallback callback;
1760 create_folder_cb (TnyFolderStore *parent_folder,
1762 TnyFolder *new_folder,
1766 ModestMailOperationPrivate *priv;
1767 CreateFolderInfo *info;
1769 info = (CreateFolderInfo *) user_data;
1770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1772 if (canceled || err) {
1773 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1775 priv->error = g_error_copy (err);
1777 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1778 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1781 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1784 /* The user will unref the new_folder */
1786 info->callback (info->mail_op, parent_folder,
1787 new_folder, info->user_data);
1789 /* Notify about operation end */
1790 modest_mail_operation_notify_end (info->mail_op);
1793 g_object_unref (info->mail_op);
1794 g_slice_free (CreateFolderInfo, info);
1798 modest_mail_operation_create_folder (ModestMailOperation *self,
1799 TnyFolderStore *parent,
1801 CreateFolderUserCallback callback,
1804 ModestMailOperationPrivate *priv;
1806 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1807 g_return_if_fail (name);
1809 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1810 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1811 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1812 g_object_ref (parent) :
1813 modest_tny_folder_get_account (TNY_FOLDER (parent));
1815 /* Check for already existing folder */
1816 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1817 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1818 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1819 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1820 _CS("ckdg_ib_folder_already_exists"));
1824 if (TNY_IS_FOLDER (parent)) {
1825 /* Check folder rules */
1826 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1827 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1828 /* Set status failed and set an error */
1829 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1830 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1831 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1832 _("mail_in_ui_folder_create_error"));
1836 if (!strcmp (name, " ") || strchr (name, '/')) {
1837 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1838 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1839 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1840 _("mail_in_ui_folder_create_error"));
1844 CreateFolderInfo *info;
1846 info = g_slice_new0 (CreateFolderInfo);
1847 info->mail_op = g_object_ref (self);
1848 info->callback = callback;
1849 info->user_data = user_data;
1851 modest_mail_operation_notify_start (self);
1853 /* Create the folder */
1854 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1857 /* Call the user callback anyway */
1859 callback (self, parent, NULL, user_data);
1860 /* Notify about operation end */
1861 modest_mail_operation_notify_end (self);
1866 modest_mail_operation_remove_folder (ModestMailOperation *self,
1868 gboolean remove_to_trash)
1870 ModestMailOperationPrivate *priv;
1871 ModestTnyFolderRules rules;
1873 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1874 g_return_if_fail (TNY_IS_FOLDER (folder));
1876 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1878 /* Check folder rules */
1879 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1880 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1881 /* Set status failed and set an error */
1882 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1883 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1884 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1885 _("mail_in_ui_folder_delete_error"));
1889 /* Get the account */
1890 priv->account = modest_tny_folder_get_account (folder);
1891 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1893 /* Delete folder or move to trash */
1894 if (remove_to_trash) {
1895 TnyFolder *trash_folder = NULL;
1896 trash_folder = modest_tny_account_get_special_folder (priv->account,
1897 TNY_FOLDER_TYPE_TRASH);
1898 /* TODO: error_handling */
1900 modest_mail_operation_notify_start (self);
1901 modest_mail_operation_xfer_folder (self, folder,
1902 TNY_FOLDER_STORE (trash_folder),
1904 g_object_unref (trash_folder);
1906 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1909 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1911 modest_mail_operation_notify_start (self);
1912 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1913 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1916 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1918 g_object_unref (parent);
1920 g_warning ("%s: could not get parent folder", __FUNCTION__);
1924 /* Notify about operation end */
1925 modest_mail_operation_notify_end (self);
1929 transfer_folder_status_cb (GObject *obj,
1933 ModestMailOperation *self;
1934 ModestMailOperationPrivate *priv;
1935 ModestMailOperationState *state;
1936 XFerFolderAsyncHelper *helper;
1938 g_return_if_fail (status != NULL);
1940 /* Show only the status information we want */
1941 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1944 helper = (XFerFolderAsyncHelper *) user_data;
1945 g_return_if_fail (helper != NULL);
1947 self = helper->mail_op;
1948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1950 priv->done = status->position;
1951 priv->total = status->of_total;
1953 state = modest_mail_operation_clone_state (self);
1955 /* This is not a GDK lock because we are a Tinymail callback
1956 * which is already GDK locked by Tinymail */
1958 /* no gdk_threads_enter (), CHECKED */
1960 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1962 /* no gdk_threads_leave (), CHECKED */
1964 g_slice_free (ModestMailOperationState, state);
1969 transfer_folder_cb (TnyFolder *folder,
1971 TnyFolderStore *into,
1972 TnyFolder *new_folder,
1976 XFerFolderAsyncHelper *helper;
1977 ModestMailOperation *self = NULL;
1978 ModestMailOperationPrivate *priv = NULL;
1980 helper = (XFerFolderAsyncHelper *) user_data;
1981 g_return_if_fail (helper != NULL);
1983 self = helper->mail_op;
1984 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1987 priv->error = g_error_copy (err);
1989 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1990 } else if (cancelled) {
1991 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1992 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1993 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1994 _("Transference of %s was cancelled."),
1995 tny_folder_get_name (folder));
1998 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2001 /* Notify about operation end */
2002 modest_mail_operation_notify_end (self);
2004 /* If user defined callback function was defined, call it */
2005 if (helper->user_callback) {
2007 /* This is not a GDK lock because we are a Tinymail callback
2008 * which is already GDK locked by Tinymail */
2010 /* no gdk_threads_enter (), CHECKED */
2011 helper->user_callback (self, new_folder, helper->user_data);
2012 /* no gdk_threads_leave () , CHECKED */
2016 g_object_unref (helper->mail_op);
2017 g_slice_free (XFerFolderAsyncHelper, helper);
2022 * This function checks if the new name is a valid name for our local
2023 * folders account. The new name could not be the same than then name
2024 * of any of the mandatory local folders
2026 * We can not rely on tinymail because tinymail does not check the
2027 * name of the virtual folders that the account could have in the case
2028 * that we're doing a rename (because it directly calls Camel which
2029 * knows nothing about our virtual folders).
2031 * In the case of an actual copy/move (i.e. move/copy a folder between
2032 * accounts) tinymail uses the tny_folder_store_create_account which
2033 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2034 * checks the new name of the folder, so this call in that case
2035 * wouldn't be needed. *But* NOTE that if tinymail changes its
2036 * implementation (if folder transfers within the same account is no
2037 * longer implemented as a rename) this call will allow Modest to work
2040 * If the new name is not valid, this function will set the status to
2041 * failed and will set also an error in the mail operation
2044 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2045 TnyFolderStore *into,
2046 const gchar *new_name)
2048 if (TNY_IS_ACCOUNT (into) &&
2049 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2050 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2052 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2054 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2055 _CS("ckdg_ib_folder_already_exists"));
2062 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2064 TnyFolderStore *parent,
2065 gboolean delete_original,
2066 XferFolderAsyncUserCallback user_callback,
2069 ModestMailOperationPrivate *priv = NULL;
2070 ModestTnyFolderRules parent_rules = 0, rules;
2071 XFerFolderAsyncHelper *helper = NULL;
2072 const gchar *folder_name = NULL;
2073 const gchar *error_msg;
2075 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2076 g_return_if_fail (TNY_IS_FOLDER (folder));
2077 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2080 folder_name = tny_folder_get_name (folder);
2082 /* Set the error msg */
2083 error_msg = _("mail_in_ui_folder_move_target_error");
2085 /* Get account and set it into mail_operation */
2086 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2087 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2088 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2090 /* Get folder rules */
2091 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2092 if (TNY_IS_FOLDER (parent))
2093 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2095 /* Apply operation constraints */
2096 if ((gpointer) parent == (gpointer) folder ||
2097 (!TNY_IS_FOLDER_STORE (parent)) ||
2098 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2101 } else if (TNY_IS_FOLDER (parent) &&
2102 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2106 } else if (TNY_IS_FOLDER (parent) &&
2107 TNY_IS_FOLDER_STORE (folder) &&
2108 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2109 TNY_FOLDER_STORE (folder))) {
2110 /* Do not move a parent into a child */
2112 } else if (TNY_IS_FOLDER_STORE (parent) &&
2113 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2114 /* Check that the new folder name is not used by any
2117 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2118 /* Check that the new folder name is not used by any
2119 special local folder */
2122 /* Create the helper */
2123 helper = g_slice_new0 (XFerFolderAsyncHelper);
2124 helper->mail_op = g_object_ref (self);
2125 helper->user_callback = user_callback;
2126 helper->user_data = user_data;
2128 /* Move/Copy folder */
2129 modest_mail_operation_notify_start (self);
2130 tny_folder_copy_async (folder,
2132 tny_folder_get_name (folder),
2135 transfer_folder_status_cb,
2141 /* Set status failed and set an error */
2142 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2143 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2144 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2147 /* Call the user callback if exists */
2149 user_callback (self, NULL, user_data);
2151 /* Notify the queue */
2152 modest_mail_operation_notify_end (self);
2156 modest_mail_operation_rename_folder (ModestMailOperation *self,
2159 XferFolderAsyncUserCallback user_callback,
2162 ModestMailOperationPrivate *priv;
2163 ModestTnyFolderRules rules;
2164 XFerFolderAsyncHelper *helper;
2166 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2167 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2168 g_return_if_fail (name);
2170 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2172 /* Get account and set it into mail_operation */
2173 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2174 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2176 /* Check folder rules */
2177 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2178 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2180 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2183 TnyFolderStore *into;
2185 into = tny_folder_get_folder_store (folder);
2187 /* Check that the new folder name is not used by any
2188 special local folder */
2189 if (new_name_valid_if_local_account (priv, into, name)) {
2190 /* Create the helper */
2191 helper = g_slice_new0 (XFerFolderAsyncHelper);
2192 helper->mail_op = g_object_ref(self);
2193 helper->user_callback = user_callback;
2194 helper->user_data = user_data;
2196 /* Rename. Camel handles folder subscription/unsubscription */
2197 modest_mail_operation_notify_start (self);
2198 tny_folder_copy_async (folder, into, name, TRUE,
2200 transfer_folder_status_cb,
2202 g_object_unref (into);
2204 g_object_unref (into);
2211 /* Set status failed and set an error */
2212 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2213 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2214 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2215 _("FIXME: unable to rename"));
2218 user_callback (self, NULL, user_data);
2220 /* Notify about operation end */
2221 modest_mail_operation_notify_end (self);
2224 /* ******************************************************************* */
2225 /* ************************** MSG ACTIONS ************************* */
2226 /* ******************************************************************* */
2229 modest_mail_operation_get_msg (ModestMailOperation *self,
2231 gboolean progress_feedback,
2232 GetMsgAsyncUserCallback user_callback,
2235 GetMsgInfo *helper = NULL;
2237 ModestMailOperationPrivate *priv;
2239 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2240 g_return_if_fail (TNY_IS_HEADER (header));
2242 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2243 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2247 /* Check memory low */
2248 if (_check_memory_low (self)) {
2250 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2251 modest_mail_operation_notify_end (self);
2255 /* Get account and set it into mail_operation */
2256 folder = tny_header_get_folder (header);
2257 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2259 /* Check for cached messages */
2260 if (progress_feedback) {
2261 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2262 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2264 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2266 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2269 /* Create the helper */
2270 helper = g_slice_new0 (GetMsgInfo);
2271 helper->header = g_object_ref (header);
2272 helper->mail_op = g_object_ref (self);
2273 helper->user_callback = user_callback;
2274 helper->user_data = user_data;
2275 helper->destroy_notify = NULL;
2276 helper->last_total_bytes = 0;
2277 helper->sum_total_bytes = 0;
2278 helper->total_bytes = tny_header_get_message_size (header);
2279 helper->more_msgs = NULL;
2281 modest_mail_operation_notify_start (self);
2283 /* notify about the start of the operation */
2284 ModestMailOperationState *state;
2285 state = modest_mail_operation_clone_state (self);
2288 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2290 g_slice_free (ModestMailOperationState, state);
2292 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2294 g_object_unref (G_OBJECT (folder));
2298 get_msg_status_cb (GObject *obj,
2302 GetMsgInfo *helper = NULL;
2304 g_return_if_fail (status != NULL);
2306 /* Show only the status information we want */
2307 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2310 helper = (GetMsgInfo *) user_data;
2311 g_return_if_fail (helper != NULL);
2313 /* Notify progress */
2314 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2315 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2319 get_msg_async_cb (TnyFolder *folder,
2325 GetMsgInfo *info = NULL;
2326 ModestMailOperationPrivate *priv = NULL;
2329 info = (GetMsgInfo *) user_data;
2331 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2334 if (info->more_msgs) {
2335 tny_iterator_next (info->more_msgs);
2336 finished = (tny_iterator_is_done (info->more_msgs));
2338 finished = (priv->done == priv->total) ? TRUE : FALSE;
2341 /* If canceled by the user, ignore the error given by Tinymail */
2345 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2347 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2349 priv->error = g_error_copy ((const GError *) err);
2350 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2353 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2354 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2357 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2358 /* Set the success status before calling the user callback */
2359 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2363 /* Call the user callback */
2364 if (info->user_callback)
2365 info->user_callback (info->mail_op, info->header, canceled,
2366 msg, err, info->user_data);
2368 /* Notify about operation end if this is the last callback */
2370 /* Free user data */
2371 if (info->destroy_notify)
2372 info->destroy_notify (info->user_data);
2374 /* Notify about operation end */
2375 modest_mail_operation_notify_end (info->mail_op);
2378 if (info->more_msgs)
2379 g_object_unref (info->more_msgs);
2380 g_object_unref (info->header);
2381 g_object_unref (info->mail_op);
2382 g_slice_free (GetMsgInfo, info);
2383 } else if (info->more_msgs) {
2384 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2385 TnyFolder *folder = tny_header_get_folder (header);
2387 g_object_unref (info->header);
2388 info->header = g_object_ref (header);
2390 /* Retrieve the next message */
2391 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2393 g_object_unref (header);
2394 g_object_unref (folder);
2396 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2401 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2402 TnyList *header_list,
2403 GetMsgAsyncUserCallback user_callback,
2405 GDestroyNotify notify)
2407 ModestMailOperationPrivate *priv = NULL;
2409 TnyIterator *iter = NULL;
2410 gboolean has_uncached_messages;
2412 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2414 /* Init mail operation */
2415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2416 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2418 priv->total = tny_list_get_length(header_list);
2420 /* Check memory low */
2421 if (_check_memory_low (self)) {
2422 if (user_callback) {
2423 TnyHeader *header = NULL;
2426 if (tny_list_get_length (header_list) > 0) {
2427 iter = tny_list_create_iterator (header_list);
2428 header = (TnyHeader *) tny_iterator_get_current (iter);
2429 g_object_unref (iter);
2431 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2433 g_object_unref (header);
2437 /* Notify about operation end */
2438 modest_mail_operation_notify_end (self);
2442 /* Check uncached messages */
2443 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2444 !has_uncached_messages && !tny_iterator_is_done (iter);
2445 tny_iterator_next (iter)) {
2448 header = (TnyHeader *) tny_iterator_get_current (iter);
2449 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2450 has_uncached_messages = TRUE;
2451 g_object_unref (header);
2453 g_object_unref (iter);
2454 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2456 /* Get account and set it into mail_operation */
2457 if (tny_list_get_length (header_list) >= 1) {
2458 TnyIterator *iterator = tny_list_create_iterator (header_list);
2459 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2461 TnyFolder *folder = tny_header_get_folder (header);
2463 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2464 g_object_unref (folder);
2466 g_object_unref (header);
2468 g_object_unref (iterator);
2471 msg_list_size = compute_message_list_size (header_list);
2473 modest_mail_operation_notify_start (self);
2474 iter = tny_list_create_iterator (header_list);
2475 if (!tny_iterator_is_done (iter)) {
2476 /* notify about the start of the operation */
2477 ModestMailOperationState *state;
2478 state = modest_mail_operation_clone_state (self);
2481 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2484 GetMsgInfo *msg_info = NULL;
2485 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2486 TnyFolder *folder = tny_header_get_folder (header);
2488 /* Create the message info */
2489 msg_info = g_slice_new0 (GetMsgInfo);
2490 msg_info->mail_op = g_object_ref (self);
2491 msg_info->header = g_object_ref (header);
2492 msg_info->more_msgs = g_object_ref (iter);
2493 msg_info->user_callback = user_callback;
2494 msg_info->user_data = user_data;
2495 msg_info->destroy_notify = notify;
2496 msg_info->last_total_bytes = 0;
2497 msg_info->sum_total_bytes = 0;
2498 msg_info->total_bytes = msg_list_size;
2500 /* The callback will call it per each header */
2501 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2503 /* Free and go on */
2504 g_object_unref (header);
2505 g_object_unref (folder);
2506 g_slice_free (ModestMailOperationState, state);
2508 g_object_unref (iter);
2513 remove_msgs_async_cb (TnyFolder *folder,
2518 gboolean expunge, leave_on_server;
2519 const gchar *account_name;
2521 TnyAccount *account;
2522 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2523 ModestMailOperation *self;
2524 ModestMailOperationPrivate *priv;
2526 self = (ModestMailOperation *) user_data;
2527 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2529 if (canceled || err) {
2530 /* If canceled by the user, ignore the error given by Tinymail */
2532 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2534 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2535 priv->error = g_error_copy ((const GError *) err);
2536 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2539 modest_mail_operation_notify_end (self);
2540 g_object_unref (self);
2544 account = tny_folder_get_account (folder);
2545 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2547 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2549 proto = tny_account_get_proto (account);
2550 g_object_unref (account);
2553 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2555 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2556 modest_tny_folder_is_remote_folder (folder) == FALSE)
2562 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2567 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2569 gboolean remove_to_trash /*ignored*/)
2571 TnyFolder *folder = NULL;
2572 ModestMailOperationPrivate *priv;
2573 TnyIterator *iter = NULL;
2574 TnyHeader *header = NULL;
2575 TnyList *remove_headers = NULL;
2576 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2578 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2579 g_return_if_fail (TNY_IS_LIST (headers));
2581 if (remove_to_trash)
2582 g_warning ("remove to trash is not implemented");
2584 if (tny_list_get_length(headers) == 0) {
2585 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2586 goto cleanup; /* nothing to do */
2589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2590 remove_headers = g_object_ref(headers);
2592 /* Get folder from first header and sync it */
2593 iter = tny_list_create_iterator (headers);
2594 header = TNY_HEADER (tny_iterator_get_current (iter));
2596 folder = tny_header_get_folder (header);
2597 if (!TNY_IS_FOLDER(folder)) {
2598 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2602 /* Don't remove messages that are being sent */
2603 if (modest_tny_folder_is_local_folder (folder)) {
2604 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2606 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2607 TnyTransportAccount *traccount = NULL;
2608 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2609 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2611 ModestTnySendQueueStatus status;
2612 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2614 if (TNY_IS_SEND_QUEUE (send_queue)) {
2615 TnyIterator *iter = tny_list_create_iterator(headers);
2616 g_object_unref(remove_headers);
2617 remove_headers = TNY_LIST(tny_simple_list_new());
2618 while (!tny_iterator_is_done(iter)) {
2620 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2621 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2622 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2623 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2624 tny_list_append(remove_headers, G_OBJECT(hdr));
2626 g_object_unref(hdr);
2628 tny_iterator_next(iter);
2630 g_object_unref(iter);
2632 g_object_unref(traccount);
2636 /* Get account and set it into mail_operation */
2637 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2638 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2639 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2641 /* remove message from folder */
2642 modest_mail_operation_notify_start (self);
2643 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2644 NULL, g_object_ref (self));
2648 g_object_unref (remove_headers);
2650 g_object_unref (header);
2652 g_object_unref (iter);
2654 g_object_unref (folder);
2658 notify_progress_of_multiple_messages (ModestMailOperation *self,
2660 gint *last_total_bytes,
2661 gint *sum_total_bytes,
2663 gboolean increment_done)
2665 ModestMailOperationPrivate *priv;
2666 ModestMailOperationState *state;
2667 gboolean is_num_bytes = FALSE;
2669 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2671 /* We know that tinymail sends us information about
2672 * transferred bytes with this particular message
2674 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2675 * I just added the 'if' so we don't get runtime warning)
2677 if (status->message)
2678 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2680 state = modest_mail_operation_clone_state (self);
2681 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2682 /* We know that we're in a different message when the
2683 total number of bytes to transfer is different. Of
2684 course it could fail if we're transferring messages
2685 of the same size, but this is a workarround */
2686 if (status->of_total != *last_total_bytes) {
2687 /* We need to increment the done when there is
2688 no information about each individual
2689 message, we need to do this in message
2690 transfers, and we don't do it for getting
2694 *sum_total_bytes += *last_total_bytes;
2695 *last_total_bytes = status->of_total;
2697 state->bytes_done += status->position + *sum_total_bytes;
2698 state->bytes_total = total_bytes;
2700 /* Notify the status change. Only notify about changes
2701 referred to bytes */
2702 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2706 g_slice_free (ModestMailOperationState, state);
2710 transfer_msgs_status_cb (GObject *obj,
2714 XFerMsgsAsyncHelper *helper;
2716 g_return_if_fail (status != NULL);
2718 /* Show only the status information we want */
2719 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2722 helper = (XFerMsgsAsyncHelper *) user_data;
2723 g_return_if_fail (helper != NULL);
2725 /* Notify progress */
2726 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2727 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2731 transfer_msgs_sync_folder_cb (TnyFolder *self,
2736 XFerMsgsAsyncHelper *helper;
2737 /* We don't care here about the results of the
2739 helper = (XFerMsgsAsyncHelper *) user_data;
2741 /* Notify about operation end */
2742 modest_mail_operation_notify_end (helper->mail_op);
2744 /* If user defined callback function was defined, call it */
2745 if (helper->user_callback)
2746 helper->user_callback (helper->mail_op, helper->user_data);
2749 if (helper->more_msgs)
2750 g_object_unref (helper->more_msgs);
2751 if (helper->headers)
2752 g_object_unref (helper->headers);
2753 if (helper->dest_folder)
2754 g_object_unref (helper->dest_folder);
2755 if (helper->mail_op)
2756 g_object_unref (helper->mail_op);
2757 g_slice_free (XFerMsgsAsyncHelper, helper);
2761 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2763 XFerMsgsAsyncHelper *helper;
2764 ModestMailOperation *self;
2765 ModestMailOperationPrivate *priv;
2766 gboolean finished = TRUE;
2768 helper = (XFerMsgsAsyncHelper *) user_data;
2769 self = helper->mail_op;
2771 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2774 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2776 priv->error = g_error_copy (err);
2778 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2779 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2780 if (helper->more_msgs) {
2781 /* We'll transfer the next message in the list */
2782 tny_iterator_next (helper->more_msgs);
2783 if (!tny_iterator_is_done (helper->more_msgs)) {
2784 GObject *next_header;
2785 g_object_unref (helper->headers);
2786 helper->headers = tny_simple_list_new ();
2787 next_header = tny_iterator_get_current (helper->more_msgs);
2788 tny_list_append (helper->headers, next_header);
2789 g_object_unref (next_header);
2795 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2800 /* Synchronize the source folder contents. This should
2801 be done by tinymail but the camel_folder_sync it's
2802 actually disabled in transfer_msgs_thread_clean
2803 because it's supposed to cause hangs */
2804 tny_folder_sync_async (folder, helper->delete,
2805 transfer_msgs_sync_folder_cb,
2808 /* Transfer more messages */
2809 tny_folder_transfer_msgs_async (folder,
2811 helper->dest_folder,
2814 transfer_msgs_status_cb,
2820 compute_message_list_size (TnyList *headers)
2825 iter = tny_list_create_iterator (headers);
2826 while (!tny_iterator_is_done (iter)) {
2827 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2828 size += tny_header_get_message_size (header);
2829 g_object_unref (header);
2830 tny_iterator_next (iter);
2832 g_object_unref (iter);
2838 compute_message_array_size (GPtrArray *headers)
2843 for (i = 0; i < headers->len; i++) {
2844 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2845 size += tny_header_get_message_size (header);
2853 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2856 gboolean delete_original,
2857 XferMsgsAsyncUserCallback user_callback,
2860 ModestMailOperationPrivate *priv = NULL;
2861 TnyIterator *iter = NULL;
2862 TnyFolder *src_folder = NULL;
2863 XFerMsgsAsyncHelper *helper = NULL;
2864 TnyHeader *header = NULL;
2865 ModestTnyFolderRules rules = 0;
2866 TnyAccount *dst_account = NULL;
2867 gboolean leave_on_server;
2869 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2870 g_return_if_fail (headers && TNY_IS_LIST (headers));
2871 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2873 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2874 priv->total = tny_list_get_length (headers);
2876 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2877 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2879 /* Apply folder rules */
2880 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2881 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2882 /* Set status failed and set an error */
2883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2884 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2885 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2886 _CS("ckct_ib_unable_to_paste_here"));
2887 /* Notify the queue */
2888 modest_mail_operation_notify_end (self);
2892 /* Get source folder */
2893 iter = tny_list_create_iterator (headers);
2894 header = TNY_HEADER (tny_iterator_get_current (iter));
2896 src_folder = tny_header_get_folder (header);
2897 g_object_unref (header);
2899 g_object_unref (iter);
2901 if (src_folder == NULL) {
2902 /* Notify the queue */
2903 modest_mail_operation_notify_end (self);
2905 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2910 /* Check folder source and destination */
2911 if (src_folder == folder) {
2912 /* Set status failed and set an error */
2913 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2914 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2915 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2916 _("mail_in_ui_folder_copy_target_error"));
2918 /* Notify the queue */
2919 modest_mail_operation_notify_end (self);
2922 g_object_unref (src_folder);
2926 /* Create the helper */
2927 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2928 helper->mail_op = g_object_ref(self);
2929 helper->dest_folder = g_object_ref(folder);
2930 helper->user_callback = user_callback;
2931 helper->user_data = user_data;
2932 helper->last_total_bytes = 0;
2933 helper->sum_total_bytes = 0;
2934 helper->total_bytes = compute_message_list_size (headers);
2936 /* Get account and set it into mail_operation */
2937 priv->account = modest_tny_folder_get_account (src_folder);
2938 dst_account = modest_tny_folder_get_account (folder);
2940 if (priv->account == dst_account) {
2941 /* Transfer all messages at once using the fast
2942 * method. Note that depending on the server this
2943 * might not be that fast, and might not be
2944 * user-cancellable either */
2945 helper->headers = g_object_ref (headers);
2946 helper->more_msgs = NULL;
2948 /* Transfer messages one by one so the user can cancel
2951 helper->headers = tny_simple_list_new ();
2952 helper->more_msgs = tny_list_create_iterator (headers);
2953 hdr = tny_iterator_get_current (helper->more_msgs);
2954 tny_list_append (helper->headers, hdr);
2955 g_object_unref (hdr);
2958 /* If leave_on_server is set to TRUE then don't use
2959 delete_original, we always pass FALSE. This is because
2960 otherwise tinymail will try to sync the source folder and
2961 this could cause an error if we're offline while
2962 transferring an already downloaded message from a POP
2964 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2965 MODEST_PROTOCOL_STORE_POP) {
2966 const gchar *account_name;
2968 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2969 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2972 leave_on_server = FALSE;
2975 /* Do not delete messages if leave on server is TRUE */
2976 helper->delete = (leave_on_server) ? FALSE : delete_original;
2978 modest_mail_operation_notify_start (self);
2979 tny_folder_transfer_msgs_async (src_folder,
2984 transfer_msgs_status_cb,
2986 g_object_unref (src_folder);
2987 g_object_unref (dst_account);
2992 on_refresh_folder (TnyFolder *folder,
2997 RefreshAsyncHelper *helper = NULL;
2998 ModestMailOperation *self = NULL;
2999 ModestMailOperationPrivate *priv = NULL;
3001 helper = (RefreshAsyncHelper *) user_data;
3002 self = helper->mail_op;
3003 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3005 g_return_if_fail(priv!=NULL);
3008 priv->error = g_error_copy (error);
3009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3014 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3015 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3016 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3017 _("Error trying to refresh the contents of %s"),
3018 tny_folder_get_name (folder));
3022 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3025 /* Call user defined callback, if it exists */
3026 if (helper->user_callback) {
3028 /* This is not a GDK lock because we are a Tinymail callback and
3029 * Tinymail already acquires the Gdk lock */
3030 helper->user_callback (self, folder, helper->user_data);
3034 g_slice_free (RefreshAsyncHelper, helper);
3036 /* Notify about operation end */
3037 modest_mail_operation_notify_end (self);
3038 g_object_unref(self);
3042 on_refresh_folder_status_update (GObject *obj,
3046 RefreshAsyncHelper *helper = NULL;
3047 ModestMailOperation *self = NULL;
3048 ModestMailOperationPrivate *priv = NULL;
3049 ModestMailOperationState *state;
3051 g_return_if_fail (user_data != NULL);
3052 g_return_if_fail (status != NULL);
3054 /* Show only the status information we want */
3055 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3058 helper = (RefreshAsyncHelper *) user_data;
3059 self = helper->mail_op;
3060 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3064 priv->done = status->position;
3065 priv->total = status->of_total;
3067 state = modest_mail_operation_clone_state (self);
3069 /* This is not a GDK lock because we are a Tinymail callback and
3070 * Tinymail already acquires the Gdk lock */
3071 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3073 g_slice_free (ModestMailOperationState, state);
3077 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3079 RefreshAsyncUserCallback user_callback,
3082 ModestMailOperationPrivate *priv = NULL;
3083 RefreshAsyncHelper *helper = NULL;
3085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3087 /* Check memory low */
3088 if (_check_memory_low (self)) {
3090 user_callback (self, folder, user_data);
3091 /* Notify about operation end */
3092 modest_mail_operation_notify_end (self);
3096 /* Get account and set it into mail_operation */
3097 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3098 priv->account = modest_tny_folder_get_account (folder);
3099 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3101 /* Create the helper */
3102 helper = g_slice_new0 (RefreshAsyncHelper);
3103 helper->mail_op = g_object_ref(self);
3104 helper->user_callback = user_callback;
3105 helper->user_data = user_data;
3107 modest_mail_operation_notify_start (self);
3109 /* notify that the operation was started */
3110 ModestMailOperationState *state;
3111 state = modest_mail_operation_clone_state (self);
3114 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3117 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3119 tny_folder_refresh_async (folder,
3121 on_refresh_folder_status_update,
3126 run_queue_stop (ModestTnySendQueue *queue,
3127 ModestMailOperation *self)
3129 ModestMailOperationPrivate *priv;
3131 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3132 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3133 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3135 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3137 modest_mail_operation_notify_end (self);
3138 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3139 g_object_unref (self);
3143 modest_mail_operation_run_queue (ModestMailOperation *self,
3144 ModestTnySendQueue *queue)
3146 ModestMailOperationPrivate *priv;
3148 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3149 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3150 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3152 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3153 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3154 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3156 modest_mail_operation_notify_start (self);
3157 g_object_ref (self);
3158 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3162 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3164 ModestMailOperation *self = (ModestMailOperation *) userdata;
3165 ModestMailOperationPrivate *priv;
3167 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3168 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3171 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3173 modest_mail_operation_notify_end (self);
3174 g_object_unref (self);
3178 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3180 ModestMailOperationPrivate *priv;
3182 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3183 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3184 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3186 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3188 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3189 priv->account = NULL;
3190 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3192 modest_mail_operation_notify_start (self);
3193 g_object_ref (self);
3194 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3198 sync_folder_finish_callback (TnyFolder *self,
3204 ModestMailOperation *mail_op;
3205 ModestMailOperationPrivate *priv;
3207 mail_op = (ModestMailOperation *) user_data;
3208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3210 /* If canceled by the user, ignore the error given by Tinymail */
3212 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3214 /* If the operation was a sync then the status is
3215 failed, but if it's part of another operation then
3216 just set it as finished with errors */
3217 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3218 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3220 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3221 priv->error = g_error_copy ((const GError *) err);
3222 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3224 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3227 modest_mail_operation_notify_end (mail_op);
3228 g_object_unref (mail_op);
3232 modest_mail_operation_sync_folder (ModestMailOperation *self,
3233 TnyFolder *folder, gboolean expunge)
3235 ModestMailOperationPrivate *priv;
3237 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3238 g_return_if_fail (TNY_IS_FOLDER (folder));
3239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3241 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3242 priv->account = modest_tny_folder_get_account (folder);
3243 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3245 modest_mail_operation_notify_start (self);
3246 g_object_ref (self);
3247 tny_folder_sync_async (folder, expunge,
3248 (TnyFolderCallback) sync_folder_finish_callback,
3253 modest_mail_operation_notify_start (ModestMailOperation *self)
3255 ModestMailOperationPrivate *priv = NULL;
3257 g_return_if_fail (self);
3259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3261 /* Ensure that all the fields are filled correctly */
3262 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3264 /* Notify the observers about the mail operation. We do not
3265 wrapp this emission because we assume that this function is
3266 always called from within the main lock */
3267 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3272 * It's used by the mail operation queue to notify the observers
3273 * attached to that signal that the operation finished. We need to use
3274 * that because tinymail does not give us the progress of a given
3275 * operation when it finishes (it directly calls the operation
3279 modest_mail_operation_notify_end (ModestMailOperation *self)
3281 ModestMailOperationPrivate *priv = NULL;
3283 g_return_if_fail (self);
3285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3287 /* Notify the observers about the mail operation end. We do
3288 not wrapp this emission because we assume that this
3289 function is always called from within the main lock */
3290 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3292 /* Remove the error user data */
3293 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3294 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3298 modest_mail_operation_get_account (ModestMailOperation *self)
3300 ModestMailOperationPrivate *priv = NULL;
3302 g_return_val_if_fail (self, NULL);
3304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3306 return (priv->account) ? g_object_ref (priv->account) : NULL;
3310 modest_mail_operation_noop (ModestMailOperation *self)
3312 ModestMailOperationPrivate *priv = NULL;
3314 g_return_if_fail (self);
3316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3317 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3318 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3322 /* This mail operation does nothing actually */
3323 modest_mail_operation_notify_start (self);
3324 modest_mail_operation_notify_end (self);
3329 modest_mail_operation_to_string (ModestMailOperation *self)
3331 const gchar *type, *status, *account_id;
3332 ModestMailOperationPrivate *priv = NULL;
3334 g_return_val_if_fail (self, NULL);
3336 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3338 /* new operations don't have anything interesting */
3339 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3340 return g_strdup_printf ("%p <new operation>", self);
3342 switch (priv->op_type) {
3343 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3344 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3345 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3346 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3347 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3348 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3349 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3350 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3351 default: type = "UNEXPECTED"; break;
3354 switch (priv->status) {
3355 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3356 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3357 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3358 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3359 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3360 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3361 default: status= "UNEXPECTED"; break;
3364 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3366 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3367 priv->done, priv->total,
3368 priv->error && priv->error->message ? priv->error->message : "");
3372 * Once the mail operations were objects this will be no longer
3373 * needed. I don't like it, but we need it for the moment
3376 _check_memory_low (ModestMailOperation *mail_op)
3378 if (modest_platform_check_memory_low (NULL, FALSE)) {
3379 ModestMailOperationPrivate *priv;
3381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3382 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3383 g_set_error (&(priv->error),
3384 MODEST_MAIL_OPERATION_ERROR,
3385 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3386 "Not enough memory to complete the operation");