1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers, guint num_elements);
100 static int compare_headers_by_date (gconstpointer a,
103 static void sync_folder_finish_callback (TnyFolder *self,
108 static gboolean _check_memory_low (ModestMailOperation *mail_op);
110 /* Helpers for the update account operation (send & receive)*/
113 ModestMailOperation *mail_op;
115 UpdateAccountCallback callback;
120 TnyFolderObserver *inbox_observer;
121 RetrieveAllCallback retrieve_all_cb;
122 gboolean interactive;
126 static void destroy_update_account_info (UpdateAccountInfo *info);
128 static void update_account_send_mail (UpdateAccountInfo *info);
130 static void update_account_get_msg_async_cb (TnyFolder *folder,
136 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
137 TnyList *new_headers);
139 enum _ModestMailOperationSignals
141 PROGRESS_CHANGED_SIGNAL,
142 OPERATION_STARTED_SIGNAL,
143 OPERATION_FINISHED_SIGNAL,
147 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
148 struct _ModestMailOperationPrivate {
154 ErrorCheckingUserCallback error_checking;
155 gpointer error_checking_user_data;
156 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
157 ModestMailOperationStatus status;
158 ModestMailOperationTypeOperation op_type;
161 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
162 MODEST_TYPE_MAIL_OPERATION, \
163 ModestMailOperationPrivate))
165 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
166 priv->status = new_status;\
171 GetMsgAsyncUserCallback user_callback;
173 TnyIterator *more_msgs;
175 ModestMailOperation *mail_op;
176 GDestroyNotify destroy_notify;
177 gint last_total_bytes;
178 gint sum_total_bytes;
182 typedef struct _RefreshAsyncHelper {
183 ModestMailOperation *mail_op;
184 RefreshAsyncUserCallback user_callback;
186 } RefreshAsyncHelper;
188 typedef struct _XFerMsgsAsyncHelper
190 ModestMailOperation *mail_op;
192 TnyIterator *more_msgs;
193 TnyFolder *dest_folder;
194 XferMsgsAsyncUserCallback user_callback;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 } XFerMsgsAsyncHelper;
202 typedef struct _XFerFolderAsyncHelper
204 ModestMailOperation *mail_op;
205 XferFolderAsyncUserCallback user_callback;
207 } XFerFolderAsyncHelper;
209 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
213 static void modest_mail_operation_create_msg (ModestMailOperation *self,
214 const gchar *from, const gchar *to,
215 const gchar *cc, const gchar *bcc,
216 const gchar *subject, const gchar *plain_body,
217 const gchar *html_body, const GList *attachments_list,
218 const GList *images_list,
219 TnyHeaderFlags priority_flags,
220 ModestMailOperationCreateMsgCallback callback,
223 static gboolean idle_notify_queue (gpointer data);
226 ModestMailOperation *mail_op;
234 GList *attachments_list;
236 TnyHeaderFlags priority_flags;
237 ModestMailOperationCreateMsgCallback callback;
243 ModestMailOperation *mail_op;
245 ModestMailOperationCreateMsgCallback callback;
250 static GObjectClass *parent_class = NULL;
252 static guint signals[NUM_SIGNALS] = {0};
255 modest_mail_operation_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMailOperationClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_mail_operation_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMailOperation),
268 (GInstanceInitFunc) modest_mail_operation_init,
271 my_type = g_type_register_static (G_TYPE_OBJECT,
272 "ModestMailOperation",
279 modest_mail_operation_class_init (ModestMailOperationClass *klass)
281 GObjectClass *gobject_class;
282 gobject_class = (GObjectClass*) klass;
284 parent_class = g_type_class_peek_parent (klass);
285 gobject_class->finalize = modest_mail_operation_finalize;
287 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
290 * ModestMailOperation::progress-changed
291 * @self: the #MailOperation that emits the signal
292 * @user_data: user data set when the signal handler was connected
294 * Emitted when the progress of a mail operation changes
296 signals[PROGRESS_CHANGED_SIGNAL] =
297 g_signal_new ("progress-changed",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
302 g_cclosure_marshal_VOID__POINTER,
303 G_TYPE_NONE, 1, G_TYPE_POINTER);
307 * This signal is issued whenever a mail operation starts, and
308 * starts mean when the tinymail operation is issued. This
309 * means that it could happen that something wrong happens and
310 * the tinymail function is never called. In this situation a
311 * operation-finished will be issued without any
314 signals[OPERATION_STARTED_SIGNAL] =
315 g_signal_new ("operation-started",
316 G_TYPE_FROM_CLASS (gobject_class),
318 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
320 g_cclosure_marshal_VOID__VOID,
325 * This signal is issued whenever a mail operation
326 * finishes. Note that this signal could be issued without any
327 * previous "operation-started" signal, because this last one
328 * is only issued when the tinymail operation is successfully
331 signals[OPERATION_FINISHED_SIGNAL] =
332 g_signal_new ("operation-finished",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
337 g_cclosure_marshal_VOID__VOID,
342 modest_mail_operation_init (ModestMailOperation *obj)
344 ModestMailOperationPrivate *priv;
346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
348 priv->account = NULL;
349 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
355 priv->error_checking = NULL;
356 priv->error_checking_user_data = NULL;
360 modest_mail_operation_finalize (GObject *obj)
362 ModestMailOperationPrivate *priv;
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
369 g_error_free (priv->error);
373 g_object_unref (priv->source);
377 g_object_unref (priv->account);
378 priv->account = NULL;
382 G_OBJECT_CLASS(parent_class)->finalize (obj);
386 modest_mail_operation_new (GObject *source)
388 ModestMailOperation *obj;
389 ModestMailOperationPrivate *priv;
391 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
395 priv->source = g_object_ref(source);
401 modest_mail_operation_new_with_error_handling (GObject *source,
402 ErrorCheckingUserCallback error_handler,
404 ErrorCheckingUserDataDestroyer error_handler_destroyer)
406 ModestMailOperation *obj;
407 ModestMailOperationPrivate *priv;
409 obj = modest_mail_operation_new (source);
410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 g_return_val_if_fail (error_handler != NULL, obj);
413 priv->error_checking = error_handler;
414 priv->error_checking_user_data = user_data;
415 priv->error_checking_user_data_destroyer = error_handler_destroyer;
421 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
423 ModestMailOperationPrivate *priv;
425 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
428 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
430 /* Call the user callback */
431 if (priv->error_checking != NULL)
432 priv->error_checking (self, priv->error_checking_user_data);
436 ModestMailOperationTypeOperation
437 modest_mail_operation_get_type_operation (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
442 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
446 return priv->op_type;
450 modest_mail_operation_is_mine (ModestMailOperation *self,
453 ModestMailOperationPrivate *priv;
455 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 if (priv->source == NULL) return FALSE;
461 return priv->source == me;
465 modest_mail_operation_get_source (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
474 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
478 return (priv->source) ? g_object_ref (priv->source) : NULL;
481 ModestMailOperationStatus
482 modest_mail_operation_get_status (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
487 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
488 MODEST_MAIL_OPERATION_STATUS_INVALID);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
492 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
493 return MODEST_MAIL_OPERATION_STATUS_INVALID;
500 modest_mail_operation_get_error (ModestMailOperation *self)
502 ModestMailOperationPrivate *priv;
504 g_return_val_if_fail (self, NULL);
505 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
510 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
518 modest_mail_operation_cancel (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
521 gboolean canceled = FALSE;
523 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
528 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
530 /* Cancel the mail operation */
531 g_return_val_if_fail (priv->account, FALSE);
532 tny_account_cancel (priv->account);
534 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
535 ModestTnySendQueue *queue;
536 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
539 /* Cancel the sending of the following next messages */
540 if (TNY_IS_SEND_QUEUE (queue))
541 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
548 modest_mail_operation_get_task_done (ModestMailOperation *self)
550 ModestMailOperationPrivate *priv;
552 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
560 modest_mail_operation_get_task_total (ModestMailOperation *self)
562 ModestMailOperationPrivate *priv;
564 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
572 modest_mail_operation_is_finished (ModestMailOperation *self)
574 ModestMailOperationPrivate *priv;
575 gboolean retval = FALSE;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
582 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
583 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
584 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
585 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
595 * Creates an image of the current state of a mail operation, the
596 * caller must free it
598 static ModestMailOperationState *
599 modest_mail_operation_clone_state (ModestMailOperation *self)
601 ModestMailOperationState *state;
602 ModestMailOperationPrivate *priv;
604 /* FIXME: this should be fixed properly
606 * in some cases, priv was NULL, so checking here to
609 g_return_val_if_fail (self, NULL);
610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
611 g_return_val_if_fail (priv, NULL);
616 state = g_slice_new (ModestMailOperationState);
618 state->status = priv->status;
619 state->op_type = priv->op_type;
620 state->done = priv->done;
621 state->total = priv->total;
622 state->finished = modest_mail_operation_is_finished (self);
623 state->bytes_done = 0;
624 state->bytes_total = 0;
629 /* ******************************************************************* */
630 /* ************************** SEND ACTIONS ************************* */
631 /* ******************************************************************* */
635 ModestMailOperation *mail_op;
640 send_mail_common_cb (gboolean cancelled,
642 SendNewMailHelper *helper)
644 ModestMailOperationPrivate *priv;
645 ModestMailOperation *self;
647 self = helper->mail_op;
648 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
650 if (cancelled || err)
654 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
655 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
656 "Error adding a msg to the send queue\n");
657 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
659 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
664 modest_mail_operation_notify_end (self);
666 g_object_unref (helper->mail_op);
667 g_slice_free (SendNewMailHelper, helper);
671 send_mail_on_sync_async_cb (TnyFolder *self,
676 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
680 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
686 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
690 idle_create_msg_cb (gpointer idle_data)
692 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
694 /* This is a GDK lock because we are an idle callback and
695 * info->callback can contain Gtk+ code */
697 gdk_threads_enter (); /* CHECKED */
698 info->callback (info->mail_op, info->msg, info->userdata);
700 g_object_unref (info->mail_op);
702 g_object_unref (info->msg);
703 g_slice_free (CreateMsgIdleInfo, info);
704 gdk_threads_leave (); /* CHECKED */
710 create_msg_thread (gpointer thread_data)
712 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
713 TnyMsg *new_msg = NULL;
714 ModestMailOperationPrivate *priv;
716 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
717 if (info->html_body == NULL) {
718 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
719 info->bcc, info->subject, info->plain_body,
720 info->attachments_list,
723 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
724 info->bcc, info->subject, info->html_body,
725 info->plain_body, info->attachments_list,
733 /* Set priority flags in message */
734 header = tny_msg_get_header (new_msg);
735 tny_header_set_flag (header, info->priority_flags);
737 /* Set attachment flags in message */
738 if (info->attachments_list != NULL)
739 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
741 g_object_unref (G_OBJECT(header));
743 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
746 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
747 "modest: failed to create a new msg\n");
755 g_free (info->plain_body);
756 g_free (info->html_body);
757 g_free (info->subject);
758 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
759 g_list_free (info->attachments_list);
760 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
761 g_list_free (info->images_list);
763 if (info->callback) {
764 CreateMsgIdleInfo *idle_info;
765 idle_info = g_slice_new0 (CreateMsgIdleInfo);
766 idle_info->mail_op = g_object_ref (info->mail_op);
767 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
768 idle_info->callback = info->callback;
769 idle_info->userdata = info->userdata;
770 g_idle_add (idle_create_msg_cb, idle_info);
772 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
775 g_object_unref (info->mail_op);
776 g_slice_free (CreateMsgInfo, info);
777 if (new_msg) g_object_unref(new_msg);
783 modest_mail_operation_create_msg (ModestMailOperation *self,
784 const gchar *from, const gchar *to,
785 const gchar *cc, const gchar *bcc,
786 const gchar *subject, const gchar *plain_body,
787 const gchar *html_body,
788 const GList *attachments_list,
789 const GList *images_list,
790 TnyHeaderFlags priority_flags,
791 ModestMailOperationCreateMsgCallback callback,
794 CreateMsgInfo *info = NULL;
796 info = g_slice_new0 (CreateMsgInfo);
797 info->mail_op = g_object_ref (self);
799 info->from = g_strdup (from);
800 info->to = g_strdup (to);
801 info->cc = g_strdup (cc);
802 info->bcc = g_strdup (bcc);
803 info->subject = g_strdup (subject);
804 info->plain_body = g_strdup (plain_body);
805 info->html_body = g_strdup (html_body);
806 info->attachments_list = g_list_copy ((GList *) attachments_list);
807 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
808 info->images_list = g_list_copy ((GList *) images_list);
809 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
810 info->priority_flags = priority_flags;
812 info->callback = callback;
813 info->userdata = userdata;
815 g_thread_create (create_msg_thread, info, FALSE, NULL);
820 TnyTransportAccount *transport_account;
825 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
829 TnySendQueue *send_queue = NULL;
830 ModestMailOperationPrivate *priv = NULL;
831 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
832 TnyFolder *draft_folder = NULL;
833 TnyFolder *outbox_folder = NULL;
834 TnyHeader *header = NULL;
836 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
839 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
840 modest_mail_operation_notify_end (self);
844 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
845 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
846 modest_mail_operation_notify_end (self);
850 /* Add message to send queue */
851 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
852 if (!TNY_IS_SEND_QUEUE(send_queue)) {
854 g_error_free (priv->error);
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
859 "modest: could not find send queue for account\n");
860 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
861 modest_mail_operation_notify_end (self);
864 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
865 helper->mail_op = g_object_ref (self);
866 helper->notify = (info->draft_msg == NULL);
868 /* Add the msg to the queue. The callback will free
870 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
872 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
876 if (info->draft_msg != NULL) {
877 TnyList *tmp_headers = NULL;
878 TnyFolder *folder = NULL;
879 TnyFolder *src_folder = NULL;
880 TnyFolderType folder_type;
881 TnyTransportAccount *transport_account = NULL;
882 SendNewMailHelper *helper = NULL;
884 /* To remove the old mail from its source folder, we need to get the
885 * transport account of the original draft message (the transport account
886 * might have been changed by the user) */
887 header = tny_msg_get_header (info->draft_msg);
888 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
889 modest_runtime_get_account_store(), header);
890 if (transport_account == NULL)
891 transport_account = g_object_ref(info->transport_account);
892 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
893 TNY_FOLDER_TYPE_DRAFTS);
894 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
895 TNY_FOLDER_TYPE_OUTBOX);
896 g_object_unref(transport_account);
899 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
901 modest_mail_operation_notify_end (self);
904 if (!outbox_folder) {
905 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
907 modest_mail_operation_notify_end (self);
911 folder = tny_msg_get_folder (info->draft_msg);
912 if (folder == NULL) {
913 modest_mail_operation_notify_end (self);
916 folder_type = modest_tny_folder_guess_folder_type (folder);
918 if (folder_type == TNY_FOLDER_TYPE_INVALID)
919 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
921 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
922 src_folder = outbox_folder;
924 src_folder = draft_folder;
926 /* Note: This can fail (with a warning) if the message is not really already in a folder,
927 * because this function requires it to have a UID. */
928 helper = g_slice_new (SendNewMailHelper);
929 helper->mail_op = g_object_ref (self);
930 helper->notify = TRUE;
932 tmp_headers = tny_simple_list_new ();
933 tny_list_append (tmp_headers, (GObject*) header);
934 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
935 g_object_unref (tmp_headers);
936 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
938 g_object_unref (folder);
943 g_object_unref (header);
945 g_object_unref (info->draft_msg);
947 g_object_unref (draft_folder);
949 g_object_unref (outbox_folder);
950 if (info->transport_account)
951 g_object_unref (info->transport_account);
952 g_slice_free (SendNewMailInfo, info);
956 modest_mail_operation_send_new_mail (ModestMailOperation *self,
957 TnyTransportAccount *transport_account,
959 const gchar *from, const gchar *to,
960 const gchar *cc, const gchar *bcc,
961 const gchar *subject, const gchar *plain_body,
962 const gchar *html_body,
963 const GList *attachments_list,
964 const GList *images_list,
965 TnyHeaderFlags priority_flags)
967 ModestMailOperationPrivate *priv = NULL;
968 SendNewMailInfo *info;
970 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
971 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
973 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
974 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
975 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
976 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
978 modest_mail_operation_notify_start (self);
980 /* Check parametters */
982 /* Set status failed and set an error */
983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
984 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
985 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
986 _("Error trying to send a mail. You need to set at least one recipient"));
987 modest_mail_operation_notify_end (self);
990 info = g_slice_new0 (SendNewMailInfo);
991 info->transport_account = transport_account;
992 if (transport_account)
993 g_object_ref (transport_account);
994 info->draft_msg = draft_msg;
996 g_object_ref (draft_msg);
999 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1000 attachments_list, images_list, priority_flags,
1001 modest_mail_operation_send_new_mail_cb, info);
1007 TnyTransportAccount *transport_account;
1009 SaveToDraftstCallback callback;
1013 ModestMailOperation *mailop;
1014 } SaveToDraftsAddMsgInfo;
1017 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1022 ModestMailOperationPrivate *priv = NULL;
1023 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1024 GError *io_error = NULL;
1026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1028 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1029 io_error = priv->error;
1033 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1034 g_error_free(priv->error);
1037 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1039 if ((!priv->error) && (info->draft_msg != NULL)) {
1040 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1041 TnyFolder *src_folder = tny_header_get_folder (header);
1043 /* Remove the old draft */
1044 tny_folder_remove_msg (src_folder, header, NULL);
1046 /* Synchronize to expunge and to update the msg counts */
1047 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1048 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1050 g_object_unref (G_OBJECT(header));
1051 g_object_unref (G_OBJECT(src_folder));
1055 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1057 g_error_free (io_error);
1060 } else if (io_error) {
1061 priv->error = io_error;
1062 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1064 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1067 /* Call the user callback */
1069 info->callback (info->mailop, info->msg, info->user_data);
1071 if (info->transport_account)
1072 g_object_unref (G_OBJECT(info->transport_account));
1073 if (info->draft_msg)
1074 g_object_unref (G_OBJECT (info->draft_msg));
1076 g_object_unref (G_OBJECT(info->drafts));
1078 g_object_unref (G_OBJECT (info->msg));
1080 modest_mail_operation_notify_end (info->mailop);
1081 g_object_unref(info->mailop);
1082 g_slice_free (SaveToDraftsAddMsgInfo, info);
1087 TnyTransportAccount *transport_account;
1089 SaveToDraftstCallback callback;
1094 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1098 TnyFolder *drafts = NULL;
1099 ModestMailOperationPrivate *priv = NULL;
1100 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1102 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1105 if (!(priv->error)) {
1106 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1107 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1108 "modest: failed to create a new msg\n");
1111 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1112 TNY_FOLDER_TYPE_DRAFTS);
1113 if (!drafts && !(priv->error)) {
1114 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1115 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1116 "modest: failed to create a new msg\n");
1120 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1121 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1122 cb_info->transport_account = g_object_ref(info->transport_account);
1123 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1124 cb_info->callback = info->callback;
1125 cb_info->user_data = info->user_data;
1126 cb_info->drafts = g_object_ref(drafts);
1127 cb_info->msg = g_object_ref(msg);
1128 cb_info->mailop = g_object_ref(self);
1129 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1132 /* Call the user callback */
1133 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1135 info->callback (self, msg, info->user_data);
1136 modest_mail_operation_notify_end (self);
1140 g_object_unref (G_OBJECT(drafts));
1141 if (info->draft_msg)
1142 g_object_unref (G_OBJECT (info->draft_msg));
1143 if (info->transport_account)
1144 g_object_unref (G_OBJECT(info->transport_account));
1145 g_slice_free (SaveToDraftsInfo, info);
1149 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1150 TnyTransportAccount *transport_account,
1152 const gchar *from, const gchar *to,
1153 const gchar *cc, const gchar *bcc,
1154 const gchar *subject, const gchar *plain_body,
1155 const gchar *html_body,
1156 const GList *attachments_list,
1157 const GList *images_list,
1158 TnyHeaderFlags priority_flags,
1159 SaveToDraftstCallback callback,
1162 ModestMailOperationPrivate *priv = NULL;
1163 SaveToDraftsInfo *info = NULL;
1165 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1166 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1170 /* Get account and set it into mail_operation */
1171 priv->account = g_object_ref (transport_account);
1172 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1174 info = g_slice_new0 (SaveToDraftsInfo);
1175 info->transport_account = g_object_ref (transport_account);
1176 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1177 info->callback = callback;
1178 info->user_data = user_data;
1180 modest_mail_operation_notify_start (self);
1181 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1182 attachments_list, images_list, priority_flags,
1183 modest_mail_operation_save_to_drafts_cb, info);
1188 ModestMailOperation *mail_op;
1189 TnyMimePart *mime_part;
1191 GetMimePartSizeCallback callback;
1193 } GetMimePartSizeInfo;
1195 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1196 /* We use this folder observer to track the headers that have been
1197 * added to a folder */
1200 TnyList *new_headers;
1201 } InternalFolderObserver;
1204 GObjectClass parent;
1205 } InternalFolderObserverClass;
1207 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1209 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1210 internal_folder_observer,
1212 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1216 foreach_add_item (gpointer header, gpointer user_data)
1218 tny_list_prepend (TNY_LIST (user_data),
1222 /* This is the method that looks for new messages in a folder */
1224 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1226 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1228 TnyFolderChangeChanged changed;
1230 changed = tny_folder_change_get_changed (change);
1232 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1235 /* Get added headers */
1236 list = tny_simple_list_new ();
1237 tny_folder_change_get_added_headers (change, list);
1239 /* Add them to the folder observer */
1240 tny_list_foreach (list, foreach_add_item,
1241 derived->new_headers);
1243 g_object_unref (G_OBJECT (list));
1248 internal_folder_observer_init (InternalFolderObserver *self)
1250 self->new_headers = tny_simple_list_new ();
1253 internal_folder_observer_finalize (GObject *object)
1255 InternalFolderObserver *self;
1257 self = (InternalFolderObserver *) object;
1258 g_object_unref (self->new_headers);
1260 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1263 tny_folder_observer_init (TnyFolderObserverIface *iface)
1265 iface->update = internal_folder_observer_update;
1268 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1270 GObjectClass *object_class;
1272 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1273 object_class = (GObjectClass*) klass;
1274 object_class->finalize = internal_folder_observer_finalize;
1278 destroy_update_account_info (UpdateAccountInfo *info)
1280 g_free (info->account_name);
1281 g_object_unref (info->folders);
1282 g_object_unref (info->mail_op);
1283 g_slice_free (UpdateAccountInfo, info);
1288 update_account_send_mail (UpdateAccountInfo *info)
1290 TnyTransportAccount *transport_account = NULL;
1292 /* Get the transport account */
1293 transport_account = (TnyTransportAccount *)
1294 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1295 info->account_name);
1297 if (transport_account) {
1298 ModestTnySendQueue *send_queue;
1302 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1303 g_object_unref (transport_account);
1305 if (TNY_IS_SEND_QUEUE (send_queue)) {
1306 /* Get outbox folder */
1307 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1308 if (outbox) { /* this could fail in some cases */
1309 num_messages = tny_folder_get_all_count (outbox);
1310 g_object_unref (outbox);
1312 g_warning ("%s: could not get outbox", __FUNCTION__);
1316 if (num_messages != 0) {
1317 /* Reenable suspended items */
1318 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1321 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1322 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1330 update_account_get_msg_async_cb (TnyFolder *folder,
1336 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1337 ModestMailOperationPrivate *priv;
1339 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1342 if (TNY_IS_MSG (msg)) {
1343 TnyHeader *header = tny_msg_get_header (msg);
1346 ModestMailOperationState *state;
1347 state = modest_mail_operation_clone_state (msg_info->mail_op);
1348 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1349 state->bytes_done = msg_info->sum_total_bytes;
1350 state->bytes_total = msg_info->total_bytes;
1352 /* Notify the status change. Only notify about changes
1353 referred to bytes */
1354 g_signal_emit (G_OBJECT (msg_info->mail_op),
1355 signals[PROGRESS_CHANGED_SIGNAL],
1358 g_object_unref (header);
1359 g_slice_free (ModestMailOperationState, state);
1363 if (priv->done == priv->total) {
1364 TnyList *new_headers;
1365 UpdateAccountInfo *info;
1367 /* After getting all the messages send the ones in the
1369 info = (UpdateAccountInfo *) msg_info->user_data;
1370 update_account_send_mail (info);
1372 /* Check if the operation was a success */
1374 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1376 /* Call the user callback and free */
1377 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1378 update_account_notify_user_and_free (info, new_headers);
1379 g_object_unref (new_headers);
1381 /* Delete the helper */
1382 g_object_unref (msg_info->more_msgs);
1383 g_object_unref (msg_info->mail_op);
1384 g_slice_free (GetMsgInfo, msg_info);
1389 update_account_notify_user_and_free (UpdateAccountInfo *info,
1390 TnyList *new_headers)
1392 /* Set the account back to not busy */
1393 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1394 info->account_name, FALSE);
1398 info->callback (info->mail_op, new_headers, info->user_data);
1400 /* Mail operation end */
1401 modest_mail_operation_notify_end (info->mail_op);
1405 g_object_unref (new_headers);
1406 destroy_update_account_info (info);
1410 inbox_refreshed_cb (TnyFolder *inbox,
1415 UpdateAccountInfo *info;
1416 ModestMailOperationPrivate *priv;
1417 TnyIterator *new_headers_iter;
1418 GPtrArray *new_headers_array = NULL;
1419 gint max_size, retrieve_limit, i;
1420 ModestAccountMgr *mgr;
1421 ModestAccountRetrieveType retrieve_type;
1422 TnyList *new_headers = NULL;
1423 gboolean headers_only, ignore_limit;
1425 info = (UpdateAccountInfo *) user_data;
1426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1427 mgr = modest_runtime_get_account_mgr ();
1429 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1430 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1432 if (canceled || err) {
1433 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1435 priv->error = g_error_copy (err);
1437 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1438 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1441 tny_folder_remove_observer (inbox, info->inbox_observer);
1442 g_object_unref (info->inbox_observer);
1443 info->inbox_observer = NULL;
1445 /* Notify the user about the error and then exit */
1446 update_account_notify_user_and_free (info, NULL);
1451 /* Try to send anyway */
1455 /* Get the message max size */
1456 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1457 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1459 max_size = G_MAXINT;
1461 max_size = max_size * KB;
1463 /* Create the new headers array. We need it to sort the
1464 new headers by date */
1465 new_headers_array = g_ptr_array_new ();
1466 if (info->inbox_observer) {
1467 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1468 while (!tny_iterator_is_done (new_headers_iter)) {
1469 TnyHeader *header = NULL;
1471 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1472 /* Apply per-message size limits */
1473 if (tny_header_get_message_size (header) < max_size)
1474 g_ptr_array_add (new_headers_array, g_object_ref (header));
1476 g_object_unref (header);
1477 tny_iterator_next (new_headers_iter);
1479 g_object_unref (new_headers_iter);
1481 tny_folder_remove_observer (inbox, info->inbox_observer);
1482 g_object_unref (info->inbox_observer);
1483 info->inbox_observer = NULL;
1486 if (new_headers_array->len == 0) {
1487 g_ptr_array_free (new_headers_array, FALSE);
1491 /* Get per-account message amount retrieval limit */
1492 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1493 if (retrieve_limit == 0)
1494 retrieve_limit = G_MAXINT;
1496 /* Get per-account retrieval type */
1497 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1498 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1501 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1503 /* Ask the users if they want to retrieve all the messages
1504 even though the limit was exceeded */
1505 ignore_limit = FALSE;
1506 if (new_headers_array->len > retrieve_limit) {
1507 /* Ask the user if a callback has been specified and
1508 if the mail operation has a source (this means that
1509 was invoked by the user and not automatically by a
1511 if (info->retrieve_all_cb && priv->source)
1512 ignore_limit = info->retrieve_all_cb (priv->source,
1513 new_headers_array->len,
1517 /* Copy the headers to a list and free the array */
1518 new_headers = tny_simple_list_new ();
1519 for (i=0; i < new_headers_array->len; i++) {
1520 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1521 tny_list_append (new_headers, G_OBJECT (header));
1523 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1524 g_ptr_array_free (new_headers_array, FALSE);
1526 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1529 GetMsgInfo *msg_info;
1533 priv->total = tny_list_get_length (new_headers);
1535 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1537 iter = tny_list_create_iterator (new_headers);
1539 /* Create the message info */
1540 msg_info = g_slice_new0 (GetMsgInfo);
1541 msg_info->mail_op = g_object_ref (info->mail_op);
1542 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1543 msg_info->more_msgs = g_object_ref (iter);
1544 msg_info->user_data = info;
1546 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1547 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1548 TnyFolder *folder = tny_header_get_folder (header);
1550 /* Get message in an async way */
1551 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1554 g_object_unref (folder);
1557 tny_iterator_next (iter);
1559 g_object_unref (iter);
1561 /* The mail operation will finish when the last
1562 message is retrieved */
1566 /* If we don't have to retrieve the new messages then
1568 update_account_send_mail (info);
1570 /* Check if the operation was a success */
1572 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1574 /* Call the user callback and free */
1575 update_account_notify_user_and_free (info, new_headers);
1579 inbox_refresh_status_update (GObject *obj,
1583 UpdateAccountInfo *info = NULL;
1584 ModestMailOperation *self = NULL;
1585 ModestMailOperationPrivate *priv = NULL;
1586 ModestMailOperationState *state;
1588 g_return_if_fail (user_data != NULL);
1589 g_return_if_fail (status != NULL);
1591 /* Show only the status information we want */
1592 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1595 info = (UpdateAccountInfo *) user_data;
1596 self = info->mail_op;
1597 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1599 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1601 priv->done = status->position;
1602 priv->total = status->of_total;
1604 state = modest_mail_operation_clone_state (self);
1606 /* This is not a GDK lock because we are a Tinymail callback and
1607 * Tinymail already acquires the Gdk lock */
1608 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1610 g_slice_free (ModestMailOperationState, state);
1614 recurse_folders_async_cb (TnyFolderStore *folder_store,
1620 UpdateAccountInfo *info;
1621 ModestMailOperationPrivate *priv;
1623 info = (UpdateAccountInfo *) user_data;
1624 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1626 if (err || canceled) {
1627 /* If the error was previosly set by another callback
1628 don't set it again */
1630 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1632 priv->error = g_error_copy (err);
1634 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1635 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1639 /* We're not getting INBOX children if we don't want to poke all */
1640 TnyIterator *iter = tny_list_create_iterator (list);
1641 while (!tny_iterator_is_done (iter)) {
1642 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1644 /* Add to the list of all folders */
1645 tny_list_append (info->folders, (GObject *) folder);
1647 if (info->poke_all) {
1648 TnyList *folders = tny_simple_list_new ();
1649 /* Add pending call */
1650 info->pending_calls++;
1652 tny_folder_store_get_folders_async (folder, folders, NULL,
1653 recurse_folders_async_cb,
1655 g_object_unref (folders);
1658 g_object_unref (G_OBJECT (folder));
1660 tny_iterator_next (iter);
1662 g_object_unref (G_OBJECT (iter));
1665 /* Remove my own pending call */
1666 info->pending_calls--;
1668 /* This means that we have all the folders */
1669 if (info->pending_calls == 0) {
1670 TnyIterator *iter_all_folders;
1671 TnyFolder *inbox = NULL;
1673 /* If there was any error do not continue */
1675 update_account_notify_user_and_free (info, NULL);
1679 iter_all_folders = tny_list_create_iterator (info->folders);
1681 /* Do a poke status over all folders */
1682 while (!tny_iterator_is_done (iter_all_folders) &&
1683 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1684 TnyFolder *folder = NULL;
1686 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1688 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1689 /* Get a reference to the INBOX */
1690 inbox = g_object_ref (folder);
1692 /* Issue a poke status over the folder */
1694 tny_folder_poke_status (folder);
1697 /* Free and go to next */
1698 g_object_unref (folder);
1699 tny_iterator_next (iter_all_folders);
1701 g_object_unref (iter_all_folders);
1703 /* Refresh the INBOX */
1705 /* Refresh the folder. Our observer receives
1706 * the new emails during folder refreshes, so
1707 * we can use observer->new_headers
1709 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1710 tny_folder_add_observer (inbox, info->inbox_observer);
1712 /* Refresh the INBOX */
1713 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1714 g_object_unref (inbox);
1716 /* We could not perform the inbox refresh but
1717 we'll try to send mails anyway */
1718 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1724 modest_mail_operation_update_account (ModestMailOperation *self,
1725 const gchar *account_name,
1727 gboolean interactive,
1728 RetrieveAllCallback retrieve_all_cb,
1729 UpdateAccountCallback callback,
1732 UpdateAccountInfo *info = NULL;
1733 ModestMailOperationPrivate *priv = NULL;
1734 ModestTnyAccountStore *account_store = NULL;
1736 ModestMailOperationState *state;
1738 /* Init mail operation */
1739 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1742 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1743 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1745 /* Get the store account */
1746 account_store = modest_runtime_get_account_store ();
1748 modest_tny_account_store_get_server_account (account_store,
1750 TNY_ACCOUNT_TYPE_STORE);
1752 /* The above function could return NULL */
1753 if (!priv->account) {
1754 /* Check if the operation was a success */
1755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1756 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1758 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1760 /* Call the user callback */
1762 callback (self, NULL, user_data);
1764 /* Notify about operation end */
1765 modest_mail_operation_notify_end (self);
1770 /* We have once seen priv->account getting finalized during this code,
1771 * therefore adding a reference (bug #82296) */
1773 g_object_ref (priv->account);
1775 /* Create the helper object */
1776 info = g_slice_new0 (UpdateAccountInfo);
1777 info->pending_calls = 1;
1778 info->folders = tny_simple_list_new ();
1779 info->mail_op = g_object_ref (self);
1780 info->poke_all = poke_all;
1781 info->interactive = interactive;
1782 info->account_name = g_strdup (account_name);
1783 info->callback = callback;
1784 info->user_data = user_data;
1785 info->retrieve_all_cb = retrieve_all_cb;
1787 /* Set account busy */
1788 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1789 modest_mail_operation_notify_start (self);
1791 /* notify about the start of the operation */
1792 state = modest_mail_operation_clone_state (self);
1796 /* Start notifying progress */
1797 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1798 g_slice_free (ModestMailOperationState, state);
1800 /* Get all folders and continue in the callback */
1801 folders = tny_simple_list_new ();
1802 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1804 recurse_folders_async_cb,
1806 g_object_unref (folders);
1808 g_object_unref (priv->account);
1813 * Used to notify the queue from the main
1814 * loop. We call it inside an idle call to achieve that
1817 idle_notify_queue (gpointer data)
1819 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1821 gdk_threads_enter ();
1822 modest_mail_operation_notify_end (mail_op);
1823 gdk_threads_leave ();
1824 g_object_unref (mail_op);
1830 compare_headers_by_date (gconstpointer a,
1833 TnyHeader **header1, **header2;
1834 time_t sent1, sent2;
1836 header1 = (TnyHeader **) a;
1837 header2 = (TnyHeader **) b;
1839 sent1 = tny_header_get_date_sent (*header1);
1840 sent2 = tny_header_get_date_sent (*header2);
1842 /* We want the most recent ones (greater time_t) at the
1851 /* ******************************************************************* */
1852 /* ************************** STORE ACTIONS ************************* */
1853 /* ******************************************************************* */
1856 ModestMailOperation *mail_op;
1857 CreateFolderUserCallback callback;
1863 create_folder_cb (TnyFolderStore *parent_folder,
1865 TnyFolder *new_folder,
1869 ModestMailOperationPrivate *priv;
1870 CreateFolderInfo *info;
1872 info = (CreateFolderInfo *) user_data;
1873 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1875 if (canceled || err) {
1876 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1878 priv->error = g_error_copy (err);
1880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1881 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1884 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1887 /* The user will unref the new_folder */
1889 info->callback (info->mail_op, parent_folder,
1890 new_folder, info->user_data);
1892 /* Notify about operation end */
1893 modest_mail_operation_notify_end (info->mail_op);
1896 g_object_unref (info->mail_op);
1897 g_slice_free (CreateFolderInfo, info);
1901 modest_mail_operation_create_folder (ModestMailOperation *self,
1902 TnyFolderStore *parent,
1904 CreateFolderUserCallback callback,
1907 ModestMailOperationPrivate *priv;
1909 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1910 g_return_if_fail (name);
1912 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1913 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1914 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1915 g_object_ref (parent) :
1916 modest_tny_folder_get_account (TNY_FOLDER (parent));
1918 /* Check for already existing folder */
1919 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1920 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1921 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1922 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1923 _CS("ckdg_ib_folder_already_exists"));
1927 if (TNY_IS_FOLDER (parent)) {
1928 /* Check folder rules */
1929 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1930 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1931 /* Set status failed and set an error */
1932 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1933 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1934 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1935 _("mail_in_ui_folder_create_error"));
1939 if (!strcmp (name, " ") || strchr (name, '/')) {
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1943 _("mail_in_ui_folder_create_error"));
1947 CreateFolderInfo *info;
1949 info = g_slice_new0 (CreateFolderInfo);
1950 info->mail_op = g_object_ref (self);
1951 info->callback = callback;
1952 info->user_data = user_data;
1954 modest_mail_operation_notify_start (self);
1956 /* Create the folder */
1957 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1960 /* Call the user callback anyway */
1962 callback (self, parent, NULL, user_data);
1963 /* Notify about operation end */
1964 modest_mail_operation_notify_end (self);
1969 modest_mail_operation_remove_folder (ModestMailOperation *self,
1971 gboolean remove_to_trash)
1973 ModestMailOperationPrivate *priv;
1974 ModestTnyFolderRules rules;
1976 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1977 g_return_if_fail (TNY_IS_FOLDER (folder));
1979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1981 /* Check folder rules */
1982 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1983 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1984 /* Set status failed and set an error */
1985 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1986 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1987 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1988 _("mail_in_ui_folder_delete_error"));
1992 /* Get the account */
1993 priv->account = modest_tny_folder_get_account (folder);
1994 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1996 /* Delete folder or move to trash */
1997 if (remove_to_trash) {
1998 TnyFolder *trash_folder = NULL;
1999 trash_folder = modest_tny_account_get_special_folder (priv->account,
2000 TNY_FOLDER_TYPE_TRASH);
2001 /* TODO: error_handling */
2003 modest_mail_operation_notify_start (self);
2004 modest_mail_operation_xfer_folder (self, folder,
2005 TNY_FOLDER_STORE (trash_folder),
2007 g_object_unref (trash_folder);
2009 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2012 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2014 modest_mail_operation_notify_start (self);
2015 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2016 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2019 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2021 g_object_unref (parent);
2023 g_warning ("%s: could not get parent folder", __FUNCTION__);
2027 /* Notify about operation end */
2028 modest_mail_operation_notify_end (self);
2032 transfer_folder_status_cb (GObject *obj,
2036 ModestMailOperation *self;
2037 ModestMailOperationPrivate *priv;
2038 ModestMailOperationState *state;
2039 XFerFolderAsyncHelper *helper;
2041 g_return_if_fail (status != NULL);
2043 /* Show only the status information we want */
2044 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2047 helper = (XFerFolderAsyncHelper *) user_data;
2048 g_return_if_fail (helper != NULL);
2050 self = helper->mail_op;
2051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2053 priv->done = status->position;
2054 priv->total = status->of_total;
2056 state = modest_mail_operation_clone_state (self);
2058 /* This is not a GDK lock because we are a Tinymail callback
2059 * which is already GDK locked by Tinymail */
2061 /* no gdk_threads_enter (), CHECKED */
2063 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2065 /* no gdk_threads_leave (), CHECKED */
2067 g_slice_free (ModestMailOperationState, state);
2072 transfer_folder_cb (TnyFolder *folder,
2074 TnyFolderStore *into,
2075 TnyFolder *new_folder,
2079 XFerFolderAsyncHelper *helper;
2080 ModestMailOperation *self = NULL;
2081 ModestMailOperationPrivate *priv = NULL;
2083 helper = (XFerFolderAsyncHelper *) user_data;
2084 g_return_if_fail (helper != NULL);
2086 self = helper->mail_op;
2087 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2090 priv->error = g_error_copy (err);
2092 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2093 } else if (cancelled) {
2094 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2095 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2096 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2097 _("Transference of %s was cancelled."),
2098 tny_folder_get_name (folder));
2101 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2104 /* Notify about operation end */
2105 modest_mail_operation_notify_end (self);
2107 /* If user defined callback function was defined, call it */
2108 if (helper->user_callback) {
2110 /* This is not a GDK lock because we are a Tinymail callback
2111 * which is already GDK locked by Tinymail */
2113 /* no gdk_threads_enter (), CHECKED */
2114 helper->user_callback (self, new_folder, helper->user_data);
2115 /* no gdk_threads_leave () , CHECKED */
2119 g_object_unref (helper->mail_op);
2120 g_slice_free (XFerFolderAsyncHelper, helper);
2125 * This function checks if the new name is a valid name for our local
2126 * folders account. The new name could not be the same than then name
2127 * of any of the mandatory local folders
2129 * We can not rely on tinymail because tinymail does not check the
2130 * name of the virtual folders that the account could have in the case
2131 * that we're doing a rename (because it directly calls Camel which
2132 * knows nothing about our virtual folders).
2134 * In the case of an actual copy/move (i.e. move/copy a folder between
2135 * accounts) tinymail uses the tny_folder_store_create_account which
2136 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2137 * checks the new name of the folder, so this call in that case
2138 * wouldn't be needed. *But* NOTE that if tinymail changes its
2139 * implementation (if folder transfers within the same account is no
2140 * longer implemented as a rename) this call will allow Modest to work
2143 * If the new name is not valid, this function will set the status to
2144 * failed and will set also an error in the mail operation
2147 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2148 TnyFolderStore *into,
2149 const gchar *new_name)
2151 if (TNY_IS_ACCOUNT (into) &&
2152 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2153 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2155 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2156 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2157 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2158 _CS("ckdg_ib_folder_already_exists"));
2165 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2167 TnyFolderStore *parent,
2168 gboolean delete_original,
2169 XferFolderAsyncUserCallback user_callback,
2172 ModestMailOperationPrivate *priv = NULL;
2173 ModestTnyFolderRules parent_rules = 0, rules;
2174 XFerFolderAsyncHelper *helper = NULL;
2175 const gchar *folder_name = NULL;
2176 const gchar *error_msg;
2178 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2179 g_return_if_fail (TNY_IS_FOLDER (folder));
2180 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2183 folder_name = tny_folder_get_name (folder);
2185 /* Set the error msg */
2186 error_msg = _("mail_in_ui_folder_move_target_error");
2188 /* Get account and set it into mail_operation */
2189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2190 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2191 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2193 /* Get folder rules */
2194 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2195 if (TNY_IS_FOLDER (parent))
2196 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2198 /* Apply operation constraints */
2199 if ((gpointer) parent == (gpointer) folder ||
2200 (!TNY_IS_FOLDER_STORE (parent)) ||
2201 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2204 } else if (TNY_IS_FOLDER (parent) &&
2205 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2209 } else if (TNY_IS_FOLDER (parent) &&
2210 TNY_IS_FOLDER_STORE (folder) &&
2211 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2212 TNY_FOLDER_STORE (folder))) {
2213 /* Do not move a parent into a child */
2215 } else if (TNY_IS_FOLDER_STORE (parent) &&
2216 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2217 /* Check that the new folder name is not used by any
2220 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2221 /* Check that the new folder name is not used by any
2222 special local folder */
2225 /* Create the helper */
2226 helper = g_slice_new0 (XFerFolderAsyncHelper);
2227 helper->mail_op = g_object_ref (self);
2228 helper->user_callback = user_callback;
2229 helper->user_data = user_data;
2231 /* Move/Copy folder */
2232 modest_mail_operation_notify_start (self);
2233 tny_folder_copy_async (folder,
2235 tny_folder_get_name (folder),
2238 transfer_folder_status_cb,
2244 /* Set status failed and set an error */
2245 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2246 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2247 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2250 /* Call the user callback if exists */
2252 user_callback (self, NULL, user_data);
2254 /* Notify the queue */
2255 modest_mail_operation_notify_end (self);
2259 modest_mail_operation_rename_folder (ModestMailOperation *self,
2262 XferFolderAsyncUserCallback user_callback,
2265 ModestMailOperationPrivate *priv;
2266 ModestTnyFolderRules rules;
2267 XFerFolderAsyncHelper *helper;
2269 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2270 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2271 g_return_if_fail (name);
2273 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2275 /* Get account and set it into mail_operation */
2276 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2277 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2279 /* Check folder rules */
2280 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2281 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2283 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2286 TnyFolderStore *into;
2288 into = tny_folder_get_folder_store (folder);
2290 /* Check that the new folder name is not used by any
2291 special local folder */
2292 if (new_name_valid_if_local_account (priv, into, name)) {
2293 /* Create the helper */
2294 helper = g_slice_new0 (XFerFolderAsyncHelper);
2295 helper->mail_op = g_object_ref(self);
2296 helper->user_callback = user_callback;
2297 helper->user_data = user_data;
2299 /* Rename. Camel handles folder subscription/unsubscription */
2300 modest_mail_operation_notify_start (self);
2301 tny_folder_copy_async (folder, into, name, TRUE,
2303 transfer_folder_status_cb,
2305 g_object_unref (into);
2307 g_object_unref (into);
2314 /* Set status failed and set an error */
2315 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2316 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2317 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2318 _("FIXME: unable to rename"));
2321 user_callback (self, NULL, user_data);
2323 /* Notify about operation end */
2324 modest_mail_operation_notify_end (self);
2327 /* ******************************************************************* */
2328 /* ************************** MSG ACTIONS ************************* */
2329 /* ******************************************************************* */
2332 modest_mail_operation_get_msg (ModestMailOperation *self,
2334 gboolean progress_feedback,
2335 GetMsgAsyncUserCallback user_callback,
2338 GetMsgInfo *helper = NULL;
2340 ModestMailOperationPrivate *priv;
2342 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2343 g_return_if_fail (TNY_IS_HEADER (header));
2345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2350 /* Check memory low */
2351 if (_check_memory_low (self)) {
2353 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2354 modest_mail_operation_notify_end (self);
2358 /* Get account and set it into mail_operation */
2359 folder = tny_header_get_folder (header);
2360 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2362 /* Check for cached messages */
2363 if (progress_feedback) {
2364 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2365 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2367 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2369 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2372 /* Create the helper */
2373 helper = g_slice_new0 (GetMsgInfo);
2374 helper->header = g_object_ref (header);
2375 helper->mail_op = g_object_ref (self);
2376 helper->user_callback = user_callback;
2377 helper->user_data = user_data;
2378 helper->destroy_notify = NULL;
2379 helper->last_total_bytes = 0;
2380 helper->sum_total_bytes = 0;
2381 helper->total_bytes = tny_header_get_message_size (header);
2382 helper->more_msgs = NULL;
2384 modest_mail_operation_notify_start (self);
2386 /* notify about the start of the operation */
2387 ModestMailOperationState *state;
2388 state = modest_mail_operation_clone_state (self);
2391 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2393 g_slice_free (ModestMailOperationState, state);
2395 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2397 g_object_unref (G_OBJECT (folder));
2401 get_msg_status_cb (GObject *obj,
2405 GetMsgInfo *helper = NULL;
2407 g_return_if_fail (status != NULL);
2409 /* Show only the status information we want */
2410 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2413 helper = (GetMsgInfo *) user_data;
2414 g_return_if_fail (helper != NULL);
2416 /* Notify progress */
2417 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2418 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2422 get_msg_async_cb (TnyFolder *folder,
2428 GetMsgInfo *info = NULL;
2429 ModestMailOperationPrivate *priv = NULL;
2432 info = (GetMsgInfo *) user_data;
2434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2437 if (info->more_msgs) {
2438 tny_iterator_next (info->more_msgs);
2439 finished = (tny_iterator_is_done (info->more_msgs));
2441 finished = (priv->done == priv->total) ? TRUE : FALSE;
2444 /* If canceled by the user, ignore the error given by Tinymail */
2448 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2450 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2452 priv->error = g_error_copy ((const GError *) err);
2453 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2456 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2457 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2460 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2461 /* Set the success status before calling the user callback */
2462 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2466 /* Call the user callback */
2467 if (info->user_callback)
2468 info->user_callback (info->mail_op, info->header, canceled,
2469 msg, err, info->user_data);
2471 /* Notify about operation end if this is the last callback */
2473 /* Free user data */
2474 if (info->destroy_notify)
2475 info->destroy_notify (info->user_data);
2477 /* Notify about operation end */
2478 modest_mail_operation_notify_end (info->mail_op);
2481 if (info->more_msgs)
2482 g_object_unref (info->more_msgs);
2483 g_object_unref (info->header);
2484 g_object_unref (info->mail_op);
2485 g_slice_free (GetMsgInfo, info);
2486 } else if (info->more_msgs) {
2487 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2488 TnyFolder *folder = tny_header_get_folder (header);
2490 g_object_unref (info->header);
2491 info->header = g_object_ref (header);
2493 /* Retrieve the next message */
2494 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2496 g_object_unref (header);
2497 g_object_unref (folder);
2499 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2504 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2505 TnyList *header_list,
2506 GetMsgAsyncUserCallback user_callback,
2508 GDestroyNotify notify)
2510 ModestMailOperationPrivate *priv = NULL;
2512 TnyIterator *iter = NULL;
2513 gboolean has_uncached_messages;
2515 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2517 /* Init mail operation */
2518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2519 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2521 priv->total = tny_list_get_length(header_list);
2523 /* Check memory low */
2524 if (_check_memory_low (self)) {
2525 if (user_callback) {
2526 TnyHeader *header = NULL;
2529 if (tny_list_get_length (header_list) > 0) {
2530 iter = tny_list_create_iterator (header_list);
2531 header = (TnyHeader *) tny_iterator_get_current (iter);
2532 g_object_unref (iter);
2534 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2536 g_object_unref (header);
2540 /* Notify about operation end */
2541 modest_mail_operation_notify_end (self);
2545 /* Check uncached messages */
2546 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2547 !has_uncached_messages && !tny_iterator_is_done (iter);
2548 tny_iterator_next (iter)) {
2551 header = (TnyHeader *) tny_iterator_get_current (iter);
2552 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2553 has_uncached_messages = TRUE;
2554 g_object_unref (header);
2556 g_object_unref (iter);
2557 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2559 /* Get account and set it into mail_operation */
2560 if (tny_list_get_length (header_list) >= 1) {
2561 TnyIterator *iterator = tny_list_create_iterator (header_list);
2562 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2564 TnyFolder *folder = tny_header_get_folder (header);
2566 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2567 g_object_unref (folder);
2569 g_object_unref (header);
2571 g_object_unref (iterator);
2574 msg_list_size = compute_message_list_size (header_list, 0);
2576 modest_mail_operation_notify_start (self);
2577 iter = tny_list_create_iterator (header_list);
2578 if (!tny_iterator_is_done (iter)) {
2579 /* notify about the start of the operation */
2580 ModestMailOperationState *state;
2581 state = modest_mail_operation_clone_state (self);
2584 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2587 GetMsgInfo *msg_info = NULL;
2588 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2589 TnyFolder *folder = tny_header_get_folder (header);
2591 /* Create the message info */
2592 msg_info = g_slice_new0 (GetMsgInfo);
2593 msg_info->mail_op = g_object_ref (self);
2594 msg_info->header = g_object_ref (header);
2595 msg_info->more_msgs = g_object_ref (iter);
2596 msg_info->user_callback = user_callback;
2597 msg_info->user_data = user_data;
2598 msg_info->destroy_notify = notify;
2599 msg_info->last_total_bytes = 0;
2600 msg_info->sum_total_bytes = 0;
2601 msg_info->total_bytes = msg_list_size;
2603 /* The callback will call it per each header */
2604 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2606 /* Free and go on */
2607 g_object_unref (header);
2608 g_object_unref (folder);
2609 g_slice_free (ModestMailOperationState, state);
2611 g_object_unref (iter);
2616 remove_msgs_async_cb (TnyFolder *folder,
2621 gboolean expunge, leave_on_server;
2622 const gchar *account_name;
2624 TnyAccount *account;
2625 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2626 ModestMailOperation *self;
2627 ModestMailOperationPrivate *priv;
2629 self = (ModestMailOperation *) user_data;
2630 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2632 if (canceled || err) {
2633 /* If canceled by the user, ignore the error given by Tinymail */
2635 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2637 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2638 priv->error = g_error_copy ((const GError *) err);
2639 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2642 modest_mail_operation_notify_end (self);
2643 g_object_unref (self);
2647 account = tny_folder_get_account (folder);
2648 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2650 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2652 proto = tny_account_get_proto (account);
2653 g_object_unref (account);
2656 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2658 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2659 modest_tny_folder_is_remote_folder (folder) == FALSE)
2665 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2670 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2672 gboolean remove_to_trash /*ignored*/)
2674 TnyFolder *folder = NULL;
2675 ModestMailOperationPrivate *priv;
2676 TnyIterator *iter = NULL;
2677 TnyHeader *header = NULL;
2678 TnyList *remove_headers = NULL;
2679 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2681 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2682 g_return_if_fail (TNY_IS_LIST (headers));
2684 if (remove_to_trash)
2685 g_warning ("remove to trash is not implemented");
2687 if (tny_list_get_length(headers) == 0) {
2688 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2689 goto cleanup; /* nothing to do */
2692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2693 remove_headers = g_object_ref(headers);
2695 /* Get folder from first header and sync it */
2696 iter = tny_list_create_iterator (headers);
2697 header = TNY_HEADER (tny_iterator_get_current (iter));
2699 folder = tny_header_get_folder (header);
2700 if (!TNY_IS_FOLDER(folder)) {
2701 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2705 /* Don't remove messages that are being sent */
2706 if (modest_tny_folder_is_local_folder (folder)) {
2707 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2709 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2710 TnyTransportAccount *traccount = NULL;
2711 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2712 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2714 ModestTnySendQueueStatus status;
2715 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2717 if (TNY_IS_SEND_QUEUE (send_queue)) {
2718 TnyIterator *iter = tny_list_create_iterator(headers);
2719 g_object_unref(remove_headers);
2720 remove_headers = TNY_LIST(tny_simple_list_new());
2721 while (!tny_iterator_is_done(iter)) {
2723 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2724 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2725 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2726 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2727 tny_list_append(remove_headers, G_OBJECT(hdr));
2729 g_object_unref(hdr);
2731 tny_iterator_next(iter);
2733 g_object_unref(iter);
2735 g_object_unref(traccount);
2739 /* Get account and set it into mail_operation */
2740 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2741 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2742 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2744 /* remove message from folder */
2745 modest_mail_operation_notify_start (self);
2746 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2747 NULL, g_object_ref (self));
2751 g_object_unref (remove_headers);
2753 g_object_unref (header);
2755 g_object_unref (iter);
2757 g_object_unref (folder);
2761 notify_progress_of_multiple_messages (ModestMailOperation *self,
2763 gint *last_total_bytes,
2764 gint *sum_total_bytes,
2766 gboolean increment_done)
2768 ModestMailOperationPrivate *priv;
2769 ModestMailOperationState *state;
2770 gboolean is_num_bytes = FALSE;
2772 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2774 /* We know that tinymail sends us information about
2775 * transferred bytes with this particular message
2777 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2778 * I just added the 'if' so we don't get runtime warning)
2780 if (status->message)
2781 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2783 state = modest_mail_operation_clone_state (self);
2784 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2785 /* We know that we're in a different message when the
2786 total number of bytes to transfer is different. Of
2787 course it could fail if we're transferring messages
2788 of the same size, but this is a workarround */
2789 if (status->of_total != *last_total_bytes) {
2790 /* We need to increment the done when there is
2791 no information about each individual
2792 message, we need to do this in message
2793 transfers, and we don't do it for getting
2797 *sum_total_bytes += *last_total_bytes;
2798 *last_total_bytes = status->of_total;
2800 state->bytes_done += status->position + *sum_total_bytes;
2801 state->bytes_total = total_bytes;
2803 /* Notify the status change. Only notify about changes
2804 referred to bytes */
2805 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2809 g_slice_free (ModestMailOperationState, state);
2813 transfer_msgs_status_cb (GObject *obj,
2817 XFerMsgsAsyncHelper *helper;
2819 g_return_if_fail (status != NULL);
2821 /* Show only the status information we want */
2822 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2825 helper = (XFerMsgsAsyncHelper *) user_data;
2826 g_return_if_fail (helper != NULL);
2828 /* Notify progress */
2829 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2830 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2834 transfer_msgs_sync_folder_cb (TnyFolder *self,
2839 XFerMsgsAsyncHelper *helper;
2840 /* We don't care here about the results of the
2842 helper = (XFerMsgsAsyncHelper *) user_data;
2844 /* Notify about operation end */
2845 modest_mail_operation_notify_end (helper->mail_op);
2847 /* If user defined callback function was defined, call it */
2848 if (helper->user_callback)
2849 helper->user_callback (helper->mail_op, helper->user_data);
2852 if (helper->more_msgs)
2853 g_object_unref (helper->more_msgs);
2854 if (helper->headers)
2855 g_object_unref (helper->headers);
2856 if (helper->dest_folder)
2857 g_object_unref (helper->dest_folder);
2858 if (helper->mail_op)
2859 g_object_unref (helper->mail_op);
2860 g_slice_free (XFerMsgsAsyncHelper, helper);
2864 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2866 XFerMsgsAsyncHelper *helper;
2867 ModestMailOperation *self;
2868 ModestMailOperationPrivate *priv;
2869 gboolean finished = TRUE;
2871 helper = (XFerMsgsAsyncHelper *) user_data;
2872 self = helper->mail_op;
2874 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2877 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2879 priv->error = g_error_copy (err);
2881 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2882 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2883 if (helper->more_msgs) {
2884 /* We'll transfer the next message in the list */
2885 tny_iterator_next (helper->more_msgs);
2886 if (!tny_iterator_is_done (helper->more_msgs)) {
2887 GObject *next_header;
2888 g_object_unref (helper->headers);
2889 helper->headers = tny_simple_list_new ();
2890 next_header = tny_iterator_get_current (helper->more_msgs);
2891 tny_list_append (helper->headers, next_header);
2892 g_object_unref (next_header);
2898 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2903 /* Synchronize the source folder contents. This should
2904 be done by tinymail but the camel_folder_sync it's
2905 actually disabled in transfer_msgs_thread_clean
2906 because it's supposed to cause hangs */
2907 tny_folder_sync_async (folder, helper->delete,
2908 transfer_msgs_sync_folder_cb,
2911 /* Transfer more messages */
2912 tny_folder_transfer_msgs_async (folder,
2914 helper->dest_folder,
2917 transfer_msgs_status_cb,
2922 /* Computes the size of the messages the headers in the list belongs
2923 to. If num_elements is different from 0 then it only takes into
2924 account the first num_elements for the calculation */
2926 compute_message_list_size (TnyList *headers,
2930 guint size = 0, element = 0;
2932 /* If num_elements is not valid then take all into account */
2933 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2934 num_elements = tny_list_get_length (headers);
2936 iter = tny_list_create_iterator (headers);
2937 while (!tny_iterator_is_done (iter) && element < num_elements) {
2938 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2939 size += tny_header_get_message_size (header);
2940 g_object_unref (header);
2941 tny_iterator_next (iter);
2944 g_object_unref (iter);
2950 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2953 gboolean delete_original,
2954 XferMsgsAsyncUserCallback user_callback,
2957 ModestMailOperationPrivate *priv = NULL;
2958 TnyIterator *iter = NULL;
2959 TnyFolder *src_folder = NULL;
2960 XFerMsgsAsyncHelper *helper = NULL;
2961 TnyHeader *header = NULL;
2962 ModestTnyFolderRules rules = 0;
2963 TnyAccount *dst_account = NULL;
2964 gboolean leave_on_server;
2965 ModestMailOperationState *state;
2967 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2968 g_return_if_fail (headers && TNY_IS_LIST (headers));
2969 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2971 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2972 priv->total = tny_list_get_length (headers);
2974 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2975 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2977 /* Apply folder rules */
2978 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2979 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2980 /* Set status failed and set an error */
2981 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2982 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2983 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2984 _CS("ckct_ib_unable_to_paste_here"));
2985 /* Notify the queue */
2986 modest_mail_operation_notify_end (self);
2990 /* Get source folder */
2991 iter = tny_list_create_iterator (headers);
2992 header = TNY_HEADER (tny_iterator_get_current (iter));
2994 src_folder = tny_header_get_folder (header);
2995 g_object_unref (header);
2997 g_object_unref (iter);
2999 if (src_folder == NULL) {
3000 /* Notify the queue */
3001 modest_mail_operation_notify_end (self);
3003 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3008 /* Check folder source and destination */
3009 if (src_folder == folder) {
3010 /* Set status failed and set an error */
3011 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3012 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3013 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3014 _("mail_in_ui_folder_copy_target_error"));
3016 /* Notify the queue */
3017 modest_mail_operation_notify_end (self);
3020 g_object_unref (src_folder);
3024 /* Create the helper */
3025 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3026 helper->mail_op = g_object_ref(self);
3027 helper->dest_folder = g_object_ref(folder);
3028 helper->user_callback = user_callback;
3029 helper->user_data = user_data;
3030 helper->last_total_bytes = 0;
3031 helper->sum_total_bytes = 0;
3032 helper->total_bytes = compute_message_list_size (headers, 0);
3034 /* Get account and set it into mail_operation */
3035 priv->account = modest_tny_folder_get_account (src_folder);
3036 dst_account = modest_tny_folder_get_account (folder);
3038 if (priv->account == dst_account) {
3039 /* Transfer all messages at once using the fast
3040 * method. Note that depending on the server this
3041 * might not be that fast, and might not be
3042 * user-cancellable either */
3043 helper->headers = g_object_ref (headers);
3044 helper->more_msgs = NULL;
3046 /* Transfer messages one by one so the user can cancel
3049 helper->headers = tny_simple_list_new ();
3050 helper->more_msgs = tny_list_create_iterator (headers);
3051 hdr = tny_iterator_get_current (helper->more_msgs);
3052 tny_list_append (helper->headers, hdr);
3053 g_object_unref (hdr);
3056 /* If leave_on_server is set to TRUE then don't use
3057 delete_original, we always pass FALSE. This is because
3058 otherwise tinymail will try to sync the source folder and
3059 this could cause an error if we're offline while
3060 transferring an already downloaded message from a POP
3062 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3063 MODEST_PROTOCOL_STORE_POP) {
3064 const gchar *account_name;
3066 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3067 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3070 leave_on_server = FALSE;
3073 /* Do not delete messages if leave on server is TRUE */
3074 helper->delete = (leave_on_server) ? FALSE : delete_original;
3076 modest_mail_operation_notify_start (self);
3078 /* Start notifying progress */
3079 state = modest_mail_operation_clone_state (self);
3082 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3083 g_slice_free (ModestMailOperationState, state);
3085 tny_folder_transfer_msgs_async (src_folder,
3090 transfer_msgs_status_cb,
3092 g_object_unref (src_folder);
3093 g_object_unref (dst_account);
3098 on_refresh_folder (TnyFolder *folder,
3103 RefreshAsyncHelper *helper = NULL;
3104 ModestMailOperation *self = NULL;
3105 ModestMailOperationPrivate *priv = NULL;
3107 helper = (RefreshAsyncHelper *) user_data;
3108 self = helper->mail_op;
3109 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3111 g_return_if_fail(priv!=NULL);
3114 priv->error = g_error_copy (error);
3115 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3120 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3121 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3122 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3123 _("Error trying to refresh the contents of %s"),
3124 tny_folder_get_name (folder));
3128 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3131 /* Call user defined callback, if it exists */
3132 if (helper->user_callback) {
3134 /* This is not a GDK lock because we are a Tinymail callback and
3135 * Tinymail already acquires the Gdk lock */
3136 helper->user_callback (self, folder, helper->user_data);
3140 g_slice_free (RefreshAsyncHelper, helper);
3142 /* Notify about operation end */
3143 modest_mail_operation_notify_end (self);
3144 g_object_unref(self);
3148 on_refresh_folder_status_update (GObject *obj,
3152 RefreshAsyncHelper *helper = NULL;
3153 ModestMailOperation *self = NULL;
3154 ModestMailOperationPrivate *priv = NULL;
3155 ModestMailOperationState *state;
3157 g_return_if_fail (user_data != NULL);
3158 g_return_if_fail (status != NULL);
3160 /* Show only the status information we want */
3161 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3164 helper = (RefreshAsyncHelper *) user_data;
3165 self = helper->mail_op;
3166 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3170 priv->done = status->position;
3171 priv->total = status->of_total;
3173 state = modest_mail_operation_clone_state (self);
3175 /* This is not a GDK lock because we are a Tinymail callback and
3176 * Tinymail already acquires the Gdk lock */
3177 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3179 g_slice_free (ModestMailOperationState, state);
3183 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3185 RefreshAsyncUserCallback user_callback,
3188 ModestMailOperationPrivate *priv = NULL;
3189 RefreshAsyncHelper *helper = NULL;
3191 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3193 /* Check memory low */
3194 if (_check_memory_low (self)) {
3196 user_callback (self, folder, user_data);
3197 /* Notify about operation end */
3198 modest_mail_operation_notify_end (self);
3202 /* Get account and set it into mail_operation */
3203 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3204 priv->account = modest_tny_folder_get_account (folder);
3205 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3207 /* Create the helper */
3208 helper = g_slice_new0 (RefreshAsyncHelper);
3209 helper->mail_op = g_object_ref(self);
3210 helper->user_callback = user_callback;
3211 helper->user_data = user_data;
3213 modest_mail_operation_notify_start (self);
3215 /* notify that the operation was started */
3216 ModestMailOperationState *state;
3217 state = modest_mail_operation_clone_state (self);
3220 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3222 g_slice_free (ModestMailOperationState, state);
3224 tny_folder_refresh_async (folder,
3226 on_refresh_folder_status_update,
3231 run_queue_stop (ModestTnySendQueue *queue,
3232 ModestMailOperation *self)
3234 ModestMailOperationPrivate *priv;
3236 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3237 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3240 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3242 modest_mail_operation_notify_end (self);
3243 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3244 g_object_unref (self);
3247 modest_mail_operation_run_queue (ModestMailOperation *self,
3248 ModestTnySendQueue *queue)
3250 ModestMailOperationPrivate *priv;
3252 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3253 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3256 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3257 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3258 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3260 modest_mail_operation_notify_start (self);
3261 g_object_ref (self);
3262 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3266 sync_folder_finish_callback (TnyFolder *self,
3272 ModestMailOperation *mail_op;
3273 ModestMailOperationPrivate *priv;
3275 mail_op = (ModestMailOperation *) user_data;
3276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3278 /* If canceled by the user, ignore the error given by Tinymail */
3280 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3282 /* If the operation was a sync then the status is
3283 failed, but if it's part of another operation then
3284 just set it as finished with errors */
3285 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3286 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3288 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3289 priv->error = g_error_copy ((const GError *) err);
3290 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3292 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3295 modest_mail_operation_notify_end (mail_op);
3296 g_object_unref (mail_op);
3300 modest_mail_operation_sync_folder (ModestMailOperation *self,
3301 TnyFolder *folder, gboolean expunge)
3303 ModestMailOperationPrivate *priv;
3305 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3306 g_return_if_fail (TNY_IS_FOLDER (folder));
3307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3309 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3310 priv->account = modest_tny_folder_get_account (folder);
3311 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3313 modest_mail_operation_notify_start (self);
3314 g_object_ref (self);
3315 tny_folder_sync_async (folder, expunge,
3316 (TnyFolderCallback) sync_folder_finish_callback,
3321 modest_mail_operation_notify_start (ModestMailOperation *self)
3323 ModestMailOperationPrivate *priv = NULL;
3325 g_return_if_fail (self);
3327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3329 /* Ensure that all the fields are filled correctly */
3330 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3332 /* Notify the observers about the mail operation. We do not
3333 wrapp this emission because we assume that this function is
3334 always called from within the main lock */
3335 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3340 * It's used by the mail operation queue to notify the observers
3341 * attached to that signal that the operation finished. We need to use
3342 * that because tinymail does not give us the progress of a given
3343 * operation when it finishes (it directly calls the operation
3347 modest_mail_operation_notify_end (ModestMailOperation *self)
3349 ModestMailOperationPrivate *priv = NULL;
3351 g_return_if_fail (self);
3353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3355 /* Notify the observers about the mail operation end. We do
3356 not wrapp this emission because we assume that this
3357 function is always called from within the main lock */
3358 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3360 /* Remove the error user data */
3361 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3362 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3366 modest_mail_operation_get_account (ModestMailOperation *self)
3368 ModestMailOperationPrivate *priv = NULL;
3370 g_return_val_if_fail (self, NULL);
3372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3374 return (priv->account) ? g_object_ref (priv->account) : NULL;
3378 modest_mail_operation_noop (ModestMailOperation *self)
3380 ModestMailOperationPrivate *priv = NULL;
3382 g_return_if_fail (self);
3384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3385 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3386 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3390 /* This mail operation does nothing actually */
3391 modest_mail_operation_notify_start (self);
3392 modest_mail_operation_notify_end (self);
3397 modest_mail_operation_to_string (ModestMailOperation *self)
3399 const gchar *type, *status, *account_id;
3400 ModestMailOperationPrivate *priv = NULL;
3402 g_return_val_if_fail (self, NULL);
3404 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3406 /* new operations don't have anything interesting */
3407 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3408 return g_strdup_printf ("%p <new operation>", self);
3410 switch (priv->op_type) {
3411 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3412 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3413 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3414 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3415 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3416 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3417 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3418 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3419 default: type = "UNEXPECTED"; break;
3422 switch (priv->status) {
3423 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3424 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3425 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3426 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3427 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3428 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3429 default: status= "UNEXPECTED"; break;
3432 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3434 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3435 priv->done, priv->total,
3436 priv->error && priv->error->message ? priv->error->message : "");
3440 * Once the mail operations were objects this will be no longer
3441 * needed. I don't like it, but we need it for the moment
3444 _check_memory_low (ModestMailOperation *mail_op)
3446 if (modest_platform_check_memory_low (NULL, FALSE)) {
3447 ModestMailOperationPrivate *priv;
3449 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3450 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3451 g_set_error (&(priv->error),
3452 MODEST_MAIL_OPERATION_ERROR,
3453 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3454 "Not enough memory to complete the operation");