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;
717 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
718 if (info->html_body == NULL) {
719 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
720 info->bcc, info->subject, info->plain_body,
721 info->attachments_list, &attached,
724 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
725 info->bcc, info->subject, info->html_body,
726 info->plain_body, info->attachments_list,
727 info->images_list, &attached,
734 /* Set priority flags in message */
735 header = tny_msg_get_header (new_msg);
736 tny_header_set_flag (header, info->priority_flags);
738 /* Set attachment flags in message */
739 if (info->attachments_list != NULL && attached > 0)
740 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
742 g_object_unref (G_OBJECT(header));
744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
746 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
747 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
748 "modest: failed to create a new msg\n");
756 g_free (info->plain_body);
757 g_free (info->html_body);
758 g_free (info->subject);
759 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
760 g_list_free (info->attachments_list);
761 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
762 g_list_free (info->images_list);
764 if (info->callback) {
765 CreateMsgIdleInfo *idle_info;
766 idle_info = g_slice_new0 (CreateMsgIdleInfo);
767 idle_info->mail_op = g_object_ref (info->mail_op);
768 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
769 idle_info->callback = info->callback;
770 idle_info->userdata = info->userdata;
771 g_idle_add (idle_create_msg_cb, idle_info);
773 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
776 g_object_unref (info->mail_op);
777 g_slice_free (CreateMsgInfo, info);
778 if (new_msg) g_object_unref(new_msg);
784 modest_mail_operation_create_msg (ModestMailOperation *self,
785 const gchar *from, const gchar *to,
786 const gchar *cc, const gchar *bcc,
787 const gchar *subject, const gchar *plain_body,
788 const gchar *html_body,
789 const GList *attachments_list,
790 const GList *images_list,
791 TnyHeaderFlags priority_flags,
792 ModestMailOperationCreateMsgCallback callback,
795 CreateMsgInfo *info = NULL;
797 info = g_slice_new0 (CreateMsgInfo);
798 info->mail_op = g_object_ref (self);
800 info->from = g_strdup (from);
801 info->to = g_strdup (to);
802 info->cc = g_strdup (cc);
803 info->bcc = g_strdup (bcc);
804 info->subject = g_strdup (subject);
805 info->plain_body = g_strdup (plain_body);
806 info->html_body = g_strdup (html_body);
807 info->attachments_list = g_list_copy ((GList *) attachments_list);
808 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
809 info->images_list = g_list_copy ((GList *) images_list);
810 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
811 info->priority_flags = priority_flags;
813 info->callback = callback;
814 info->userdata = userdata;
816 g_thread_create (create_msg_thread, info, FALSE, NULL);
821 TnyTransportAccount *transport_account;
826 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
830 TnySendQueue *send_queue = NULL;
831 ModestMailOperationPrivate *priv = NULL;
832 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
833 TnyFolder *draft_folder = NULL;
834 TnyFolder *outbox_folder = NULL;
835 TnyHeader *header = NULL;
837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
840 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
841 modest_mail_operation_notify_end (self);
845 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
847 modest_mail_operation_notify_end (self);
851 /* Add message to send queue */
852 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
853 if (!TNY_IS_SEND_QUEUE(send_queue)) {
855 g_error_free (priv->error);
858 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
859 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
860 "modest: could not find send queue for account\n");
861 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
862 modest_mail_operation_notify_end (self);
865 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
866 helper->mail_op = g_object_ref (self);
867 helper->notify = (info->draft_msg == NULL);
869 /* Add the msg to the queue. The callback will free
871 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
873 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
877 if (info->draft_msg != NULL) {
878 TnyList *tmp_headers = NULL;
879 TnyFolder *folder = NULL;
880 TnyFolder *src_folder = NULL;
881 TnyFolderType folder_type;
882 TnyTransportAccount *transport_account = NULL;
883 SendNewMailHelper *helper = NULL;
885 /* To remove the old mail from its source folder, we need to get the
886 * transport account of the original draft message (the transport account
887 * might have been changed by the user) */
888 header = tny_msg_get_header (info->draft_msg);
889 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
890 modest_runtime_get_account_store(), header);
891 if (transport_account == NULL)
892 transport_account = g_object_ref(info->transport_account);
893 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
894 TNY_FOLDER_TYPE_DRAFTS);
895 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
896 TNY_FOLDER_TYPE_OUTBOX);
897 g_object_unref(transport_account);
900 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
902 modest_mail_operation_notify_end (self);
905 if (!outbox_folder) {
906 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
908 modest_mail_operation_notify_end (self);
912 folder = tny_msg_get_folder (info->draft_msg);
913 if (folder == NULL) {
914 modest_mail_operation_notify_end (self);
917 folder_type = modest_tny_folder_guess_folder_type (folder);
919 if (folder_type == TNY_FOLDER_TYPE_INVALID)
920 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
922 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
923 src_folder = outbox_folder;
925 src_folder = draft_folder;
927 /* Note: This can fail (with a warning) if the message is not really already in a folder,
928 * because this function requires it to have a UID. */
929 helper = g_slice_new (SendNewMailHelper);
930 helper->mail_op = g_object_ref (self);
931 helper->notify = TRUE;
933 tmp_headers = tny_simple_list_new ();
934 tny_list_append (tmp_headers, (GObject*) header);
935 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
936 g_object_unref (tmp_headers);
937 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
939 g_object_unref (folder);
944 g_object_unref (header);
946 g_object_unref (info->draft_msg);
948 g_object_unref (draft_folder);
950 g_object_unref (outbox_folder);
951 if (info->transport_account)
952 g_object_unref (info->transport_account);
953 g_slice_free (SendNewMailInfo, info);
957 modest_mail_operation_send_new_mail (ModestMailOperation *self,
958 TnyTransportAccount *transport_account,
960 const gchar *from, const gchar *to,
961 const gchar *cc, const gchar *bcc,
962 const gchar *subject, const gchar *plain_body,
963 const gchar *html_body,
964 const GList *attachments_list,
965 const GList *images_list,
966 TnyHeaderFlags priority_flags)
968 ModestMailOperationPrivate *priv = NULL;
969 SendNewMailInfo *info;
971 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
972 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
974 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
975 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
976 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
977 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
979 modest_mail_operation_notify_start (self);
981 /* Check parametters */
983 /* Set status failed and set an error */
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
986 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
987 _("Error trying to send a mail. You need to set at least one recipient"));
988 modest_mail_operation_notify_end (self);
991 info = g_slice_new0 (SendNewMailInfo);
992 info->transport_account = transport_account;
993 if (transport_account)
994 g_object_ref (transport_account);
995 info->draft_msg = draft_msg;
997 g_object_ref (draft_msg);
1000 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1001 attachments_list, images_list, priority_flags,
1002 modest_mail_operation_send_new_mail_cb, info);
1008 TnyTransportAccount *transport_account;
1010 SaveToDraftstCallback callback;
1014 ModestMailOperation *mailop;
1015 } SaveToDraftsAddMsgInfo;
1018 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1023 ModestMailOperationPrivate *priv = NULL;
1024 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1025 GError *io_error = NULL;
1027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1029 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1030 io_error = priv->error;
1034 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1035 g_error_free(priv->error);
1038 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1040 if ((!priv->error) && (info->draft_msg != NULL)) {
1041 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1042 TnyFolder *src_folder = tny_header_get_folder (header);
1044 /* Remove the old draft */
1045 tny_folder_remove_msg (src_folder, header, NULL);
1047 /* Synchronize to expunge and to update the msg counts */
1048 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1049 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1051 g_object_unref (G_OBJECT(header));
1052 g_object_unref (G_OBJECT(src_folder));
1056 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1058 g_error_free (io_error);
1061 } else if (io_error) {
1062 priv->error = io_error;
1063 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1068 /* Call the user callback */
1070 info->callback (info->mailop, info->msg, info->user_data);
1072 if (info->transport_account)
1073 g_object_unref (G_OBJECT(info->transport_account));
1074 if (info->draft_msg)
1075 g_object_unref (G_OBJECT (info->draft_msg));
1077 g_object_unref (G_OBJECT(info->drafts));
1079 g_object_unref (G_OBJECT (info->msg));
1081 modest_mail_operation_notify_end (info->mailop);
1082 g_object_unref(info->mailop);
1083 g_slice_free (SaveToDraftsAddMsgInfo, info);
1088 TnyTransportAccount *transport_account;
1090 SaveToDraftstCallback callback;
1095 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1099 TnyFolder *drafts = NULL;
1100 ModestMailOperationPrivate *priv = NULL;
1101 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1103 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1106 if (!(priv->error)) {
1107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1108 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1109 "modest: failed to create a new msg\n");
1112 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1113 TNY_FOLDER_TYPE_DRAFTS);
1114 if (!drafts && !(priv->error)) {
1115 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1116 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1117 "modest: failed to create a new msg\n");
1121 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1122 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1123 cb_info->transport_account = g_object_ref(info->transport_account);
1124 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1125 cb_info->callback = info->callback;
1126 cb_info->user_data = info->user_data;
1127 cb_info->drafts = g_object_ref(drafts);
1128 cb_info->msg = g_object_ref(msg);
1129 cb_info->mailop = g_object_ref(self);
1130 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1133 /* Call the user callback */
1134 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1136 info->callback (self, msg, info->user_data);
1137 modest_mail_operation_notify_end (self);
1141 g_object_unref (G_OBJECT(drafts));
1142 if (info->draft_msg)
1143 g_object_unref (G_OBJECT (info->draft_msg));
1144 if (info->transport_account)
1145 g_object_unref (G_OBJECT(info->transport_account));
1146 g_slice_free (SaveToDraftsInfo, info);
1150 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1151 TnyTransportAccount *transport_account,
1153 const gchar *from, const gchar *to,
1154 const gchar *cc, const gchar *bcc,
1155 const gchar *subject, const gchar *plain_body,
1156 const gchar *html_body,
1157 const GList *attachments_list,
1158 const GList *images_list,
1159 TnyHeaderFlags priority_flags,
1160 SaveToDraftstCallback callback,
1163 ModestMailOperationPrivate *priv = NULL;
1164 SaveToDraftsInfo *info = NULL;
1166 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1167 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1171 /* Get account and set it into mail_operation */
1172 priv->account = g_object_ref (transport_account);
1173 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1175 info = g_slice_new0 (SaveToDraftsInfo);
1176 info->transport_account = g_object_ref (transport_account);
1177 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1178 info->callback = callback;
1179 info->user_data = user_data;
1181 modest_mail_operation_notify_start (self);
1182 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1183 attachments_list, images_list, priority_flags,
1184 modest_mail_operation_save_to_drafts_cb, info);
1189 ModestMailOperation *mail_op;
1190 TnyMimePart *mime_part;
1192 GetMimePartSizeCallback callback;
1194 } GetMimePartSizeInfo;
1196 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1197 /* We use this folder observer to track the headers that have been
1198 * added to a folder */
1201 TnyList *new_headers;
1202 } InternalFolderObserver;
1205 GObjectClass parent;
1206 } InternalFolderObserverClass;
1208 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1210 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1211 internal_folder_observer,
1213 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1217 foreach_add_item (gpointer header, gpointer user_data)
1219 tny_list_prepend (TNY_LIST (user_data),
1223 /* This is the method that looks for new messages in a folder */
1225 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1227 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1229 TnyFolderChangeChanged changed;
1231 changed = tny_folder_change_get_changed (change);
1233 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1236 /* Get added headers */
1237 list = tny_simple_list_new ();
1238 tny_folder_change_get_added_headers (change, list);
1240 /* Add them to the folder observer */
1241 tny_list_foreach (list, foreach_add_item,
1242 derived->new_headers);
1244 g_object_unref (G_OBJECT (list));
1249 internal_folder_observer_init (InternalFolderObserver *self)
1251 self->new_headers = tny_simple_list_new ();
1254 internal_folder_observer_finalize (GObject *object)
1256 InternalFolderObserver *self;
1258 self = (InternalFolderObserver *) object;
1259 g_object_unref (self->new_headers);
1261 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1264 tny_folder_observer_init (TnyFolderObserverIface *iface)
1266 iface->update = internal_folder_observer_update;
1269 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1271 GObjectClass *object_class;
1273 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1274 object_class = (GObjectClass*) klass;
1275 object_class->finalize = internal_folder_observer_finalize;
1279 destroy_update_account_info (UpdateAccountInfo *info)
1281 g_free (info->account_name);
1282 g_object_unref (info->folders);
1283 g_object_unref (info->mail_op);
1284 g_slice_free (UpdateAccountInfo, info);
1289 update_account_send_mail (UpdateAccountInfo *info)
1291 TnyTransportAccount *transport_account = NULL;
1292 ModestTnyAccountStore *account_store;
1294 account_store = modest_runtime_get_account_store ();
1296 /* We don't try to send messages while sending mails is blocked */
1297 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1300 /* Get the transport account */
1301 transport_account = (TnyTransportAccount *)
1302 modest_tny_account_store_get_transport_account_for_open_connection (account_store,
1303 info->account_name);
1305 if (transport_account) {
1306 ModestTnySendQueue *send_queue;
1310 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1311 g_object_unref (transport_account);
1313 if (TNY_IS_SEND_QUEUE (send_queue)) {
1314 /* Get outbox folder */
1315 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1316 if (outbox) { /* this could fail in some cases */
1317 num_messages = tny_folder_get_all_count (outbox);
1318 g_object_unref (outbox);
1320 g_warning ("%s: could not get outbox", __FUNCTION__);
1324 if (num_messages != 0) {
1325 /* Reenable suspended items */
1326 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1329 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1330 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1338 update_account_get_msg_async_cb (TnyFolder *folder,
1344 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1345 ModestMailOperationPrivate *priv;
1347 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1350 if (TNY_IS_MSG (msg)) {
1351 TnyHeader *header = tny_msg_get_header (msg);
1354 ModestMailOperationState *state;
1355 state = modest_mail_operation_clone_state (msg_info->mail_op);
1356 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1357 state->bytes_done = msg_info->sum_total_bytes;
1358 state->bytes_total = msg_info->total_bytes;
1360 /* Notify the status change. Only notify about changes
1361 referred to bytes */
1362 g_signal_emit (G_OBJECT (msg_info->mail_op),
1363 signals[PROGRESS_CHANGED_SIGNAL],
1366 g_object_unref (header);
1367 g_slice_free (ModestMailOperationState, state);
1371 if (priv->done == priv->total) {
1372 TnyList *new_headers;
1373 UpdateAccountInfo *info;
1375 /* After getting all the messages send the ones in the
1377 info = (UpdateAccountInfo *) msg_info->user_data;
1378 update_account_send_mail (info);
1380 /* Check if the operation was a success */
1382 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1384 /* Call the user callback and free */
1385 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1386 update_account_notify_user_and_free (info, new_headers);
1387 g_object_unref (new_headers);
1389 /* Delete the helper */
1390 g_object_unref (msg_info->more_msgs);
1391 g_object_unref (msg_info->mail_op);
1392 g_slice_free (GetMsgInfo, msg_info);
1397 update_account_notify_user_and_free (UpdateAccountInfo *info,
1398 TnyList *new_headers)
1400 /* Set the account back to not busy */
1401 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1402 info->account_name, FALSE);
1406 info->callback (info->mail_op, new_headers, info->user_data);
1408 /* Mail operation end */
1409 modest_mail_operation_notify_end (info->mail_op);
1413 g_object_unref (new_headers);
1414 destroy_update_account_info (info);
1418 inbox_refreshed_cb (TnyFolder *inbox,
1423 UpdateAccountInfo *info;
1424 ModestMailOperationPrivate *priv;
1425 TnyIterator *new_headers_iter;
1426 GPtrArray *new_headers_array = NULL;
1427 gint max_size, retrieve_limit, i;
1428 ModestAccountMgr *mgr;
1429 ModestAccountRetrieveType retrieve_type;
1430 TnyList *new_headers = NULL;
1431 gboolean headers_only, ignore_limit;
1433 info = (UpdateAccountInfo *) user_data;
1434 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1435 mgr = modest_runtime_get_account_mgr ();
1437 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1438 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1440 if (canceled || err) {
1441 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1443 priv->error = g_error_copy (err);
1445 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1446 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1449 tny_folder_remove_observer (inbox, info->inbox_observer);
1450 g_object_unref (info->inbox_observer);
1451 info->inbox_observer = NULL;
1453 /* Notify the user about the error and then exit */
1454 update_account_notify_user_and_free (info, NULL);
1459 /* Try to send anyway */
1463 /* Get the message max size */
1464 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1465 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1467 max_size = G_MAXINT;
1469 max_size = max_size * KB;
1471 /* Create the new headers array. We need it to sort the
1472 new headers by date */
1473 new_headers_array = g_ptr_array_new ();
1474 if (info->inbox_observer) {
1475 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1476 while (!tny_iterator_is_done (new_headers_iter)) {
1477 TnyHeader *header = NULL;
1479 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1480 /* Apply per-message size limits */
1481 if (tny_header_get_message_size (header) < max_size)
1482 g_ptr_array_add (new_headers_array, g_object_ref (header));
1484 g_object_unref (header);
1485 tny_iterator_next (new_headers_iter);
1487 g_object_unref (new_headers_iter);
1489 tny_folder_remove_observer (inbox, info->inbox_observer);
1490 g_object_unref (info->inbox_observer);
1491 info->inbox_observer = NULL;
1494 if (new_headers_array->len == 0) {
1495 g_ptr_array_free (new_headers_array, FALSE);
1499 /* Get per-account message amount retrieval limit */
1500 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1501 if (retrieve_limit == 0)
1502 retrieve_limit = G_MAXINT;
1504 /* Get per-account retrieval type */
1505 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1506 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1509 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1511 /* Ask the users if they want to retrieve all the messages
1512 even though the limit was exceeded */
1513 ignore_limit = FALSE;
1514 if (new_headers_array->len > retrieve_limit) {
1515 /* Ask the user if a callback has been specified and
1516 if the mail operation has a source (this means that
1517 was invoked by the user and not automatically by a
1519 if (info->retrieve_all_cb && priv->source)
1520 ignore_limit = info->retrieve_all_cb (priv->source,
1521 new_headers_array->len,
1525 /* Copy the headers to a list and free the array */
1526 new_headers = tny_simple_list_new ();
1527 for (i=0; i < new_headers_array->len; i++) {
1528 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1529 tny_list_append (new_headers, G_OBJECT (header));
1531 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1532 g_ptr_array_free (new_headers_array, FALSE);
1534 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1537 GetMsgInfo *msg_info;
1541 priv->total = tny_list_get_length (new_headers);
1543 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1545 iter = tny_list_create_iterator (new_headers);
1547 /* Create the message info */
1548 msg_info = g_slice_new0 (GetMsgInfo);
1549 msg_info->mail_op = g_object_ref (info->mail_op);
1550 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1551 msg_info->more_msgs = g_object_ref (iter);
1552 msg_info->user_data = info;
1554 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1555 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1556 TnyFolder *folder = tny_header_get_folder (header);
1558 /* Get message in an async way */
1559 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1562 g_object_unref (folder);
1565 tny_iterator_next (iter);
1567 g_object_unref (iter);
1569 /* The mail operation will finish when the last
1570 message is retrieved */
1574 /* If we don't have to retrieve the new messages then
1576 update_account_send_mail (info);
1578 /* Check if the operation was a success */
1580 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1582 /* Call the user callback and free */
1583 update_account_notify_user_and_free (info, new_headers);
1587 inbox_refresh_status_update (GObject *obj,
1591 UpdateAccountInfo *info = NULL;
1592 ModestMailOperation *self = NULL;
1593 ModestMailOperationPrivate *priv = NULL;
1594 ModestMailOperationState *state;
1596 g_return_if_fail (user_data != NULL);
1597 g_return_if_fail (status != NULL);
1599 /* Show only the status information we want */
1600 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1603 info = (UpdateAccountInfo *) user_data;
1604 self = info->mail_op;
1605 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1609 priv->done = status->position;
1610 priv->total = status->of_total;
1612 state = modest_mail_operation_clone_state (self);
1614 /* This is not a GDK lock because we are a Tinymail callback and
1615 * Tinymail already acquires the Gdk lock */
1616 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1618 g_slice_free (ModestMailOperationState, state);
1622 recurse_folders_async_cb (TnyFolderStore *folder_store,
1628 UpdateAccountInfo *info;
1629 ModestMailOperationPrivate *priv;
1631 info = (UpdateAccountInfo *) user_data;
1632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1634 if (err || canceled) {
1635 /* If the error was previosly set by another callback
1636 don't set it again */
1638 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1640 priv->error = g_error_copy (err);
1642 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1643 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1647 /* We're not getting INBOX children if we don't want to poke all */
1648 TnyIterator *iter = tny_list_create_iterator (list);
1649 while (!tny_iterator_is_done (iter)) {
1650 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1652 /* Add to the list of all folders */
1653 tny_list_append (info->folders, (GObject *) folder);
1655 if (info->poke_all) {
1656 TnyList *folders = tny_simple_list_new ();
1657 /* Add pending call */
1658 info->pending_calls++;
1660 tny_folder_store_get_folders_async (folder, folders, NULL,
1661 recurse_folders_async_cb,
1663 g_object_unref (folders);
1666 g_object_unref (G_OBJECT (folder));
1668 tny_iterator_next (iter);
1670 g_object_unref (G_OBJECT (iter));
1673 /* Remove my own pending call */
1674 info->pending_calls--;
1676 /* This means that we have all the folders */
1677 if (info->pending_calls == 0) {
1678 TnyIterator *iter_all_folders;
1679 TnyFolder *inbox = NULL;
1681 /* If there was any error do not continue */
1683 update_account_notify_user_and_free (info, NULL);
1687 iter_all_folders = tny_list_create_iterator (info->folders);
1689 /* Do a poke status over all folders */
1690 while (!tny_iterator_is_done (iter_all_folders) &&
1691 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1692 TnyFolder *folder = NULL;
1694 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1696 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1697 /* Get a reference to the INBOX */
1698 inbox = g_object_ref (folder);
1700 /* Issue a poke status over the folder */
1702 tny_folder_poke_status (folder);
1705 /* Free and go to next */
1706 g_object_unref (folder);
1707 tny_iterator_next (iter_all_folders);
1709 g_object_unref (iter_all_folders);
1711 /* Refresh the INBOX */
1713 /* Refresh the folder. Our observer receives
1714 * the new emails during folder refreshes, so
1715 * we can use observer->new_headers
1717 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1718 tny_folder_add_observer (inbox, info->inbox_observer);
1720 /* Refresh the INBOX */
1721 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1722 g_object_unref (inbox);
1724 /* We could not perform the inbox refresh but
1725 we'll try to send mails anyway */
1726 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1732 modest_mail_operation_update_account (ModestMailOperation *self,
1733 const gchar *account_name,
1735 gboolean interactive,
1736 RetrieveAllCallback retrieve_all_cb,
1737 UpdateAccountCallback callback,
1740 UpdateAccountInfo *info = NULL;
1741 ModestMailOperationPrivate *priv = NULL;
1742 ModestTnyAccountStore *account_store = NULL;
1744 ModestMailOperationState *state;
1746 /* Init mail operation */
1747 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1751 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1753 /* Get the store account */
1754 account_store = modest_runtime_get_account_store ();
1756 modest_tny_account_store_get_server_account (account_store,
1758 TNY_ACCOUNT_TYPE_STORE);
1760 /* The above function could return NULL */
1761 if (!priv->account) {
1762 /* Check if the operation was a success */
1763 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1764 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1766 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1768 /* Call the user callback */
1770 callback (self, NULL, user_data);
1772 /* Notify about operation end */
1773 modest_mail_operation_notify_end (self);
1778 /* We have once seen priv->account getting finalized during this code,
1779 * therefore adding a reference (bug #82296) */
1781 g_object_ref (priv->account);
1783 /* Create the helper object */
1784 info = g_slice_new0 (UpdateAccountInfo);
1785 info->pending_calls = 1;
1786 info->folders = tny_simple_list_new ();
1787 info->mail_op = g_object_ref (self);
1788 info->poke_all = poke_all;
1789 info->interactive = interactive;
1790 info->account_name = g_strdup (account_name);
1791 info->callback = callback;
1792 info->user_data = user_data;
1793 info->retrieve_all_cb = retrieve_all_cb;
1795 /* Set account busy */
1796 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1797 modest_mail_operation_notify_start (self);
1799 /* notify about the start of the operation */
1800 state = modest_mail_operation_clone_state (self);
1804 /* Start notifying progress */
1805 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1806 g_slice_free (ModestMailOperationState, state);
1808 /* Get all folders and continue in the callback */
1809 folders = tny_simple_list_new ();
1810 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1812 recurse_folders_async_cb,
1814 g_object_unref (folders);
1816 g_object_unref (priv->account);
1821 * Used to notify the queue from the main
1822 * loop. We call it inside an idle call to achieve that
1825 idle_notify_queue (gpointer data)
1827 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1829 gdk_threads_enter ();
1830 modest_mail_operation_notify_end (mail_op);
1831 gdk_threads_leave ();
1832 g_object_unref (mail_op);
1838 compare_headers_by_date (gconstpointer a,
1841 TnyHeader **header1, **header2;
1842 time_t sent1, sent2;
1844 header1 = (TnyHeader **) a;
1845 header2 = (TnyHeader **) b;
1847 sent1 = tny_header_get_date_sent (*header1);
1848 sent2 = tny_header_get_date_sent (*header2);
1850 /* We want the most recent ones (greater time_t) at the
1859 /* ******************************************************************* */
1860 /* ************************** STORE ACTIONS ************************* */
1861 /* ******************************************************************* */
1864 ModestMailOperation *mail_op;
1865 CreateFolderUserCallback callback;
1871 create_folder_cb (TnyFolderStore *parent_folder,
1873 TnyFolder *new_folder,
1877 ModestMailOperationPrivate *priv;
1878 CreateFolderInfo *info;
1880 info = (CreateFolderInfo *) user_data;
1881 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1883 if (canceled || err) {
1884 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1886 priv->error = g_error_copy (err);
1888 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1889 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1892 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1895 /* The user will unref the new_folder */
1897 info->callback (info->mail_op, parent_folder,
1898 new_folder, info->user_data);
1900 /* Notify about operation end */
1901 modest_mail_operation_notify_end (info->mail_op);
1904 g_object_unref (info->mail_op);
1905 g_slice_free (CreateFolderInfo, info);
1909 modest_mail_operation_create_folder (ModestMailOperation *self,
1910 TnyFolderStore *parent,
1912 CreateFolderUserCallback callback,
1915 ModestMailOperationPrivate *priv;
1917 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1918 g_return_if_fail (name);
1920 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1921 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1922 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1923 g_object_ref (parent) :
1924 modest_tny_folder_get_account (TNY_FOLDER (parent));
1926 /* Check for already existing folder */
1927 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1928 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1929 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1930 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1931 _CS("ckdg_ib_folder_already_exists"));
1935 if (TNY_IS_FOLDER (parent)) {
1936 /* Check folder rules */
1937 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1938 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1939 /* Set status failed and set an error */
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 if (!strcmp (name, " ") || strchr (name, '/')) {
1948 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1949 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1950 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1951 _("mail_in_ui_folder_create_error"));
1955 CreateFolderInfo *info;
1957 info = g_slice_new0 (CreateFolderInfo);
1958 info->mail_op = g_object_ref (self);
1959 info->callback = callback;
1960 info->user_data = user_data;
1962 modest_mail_operation_notify_start (self);
1964 /* Create the folder */
1965 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1968 /* Call the user callback anyway */
1970 callback (self, parent, NULL, user_data);
1971 /* Notify about operation end */
1972 modest_mail_operation_notify_end (self);
1977 modest_mail_operation_remove_folder (ModestMailOperation *self,
1979 gboolean remove_to_trash)
1981 ModestMailOperationPrivate *priv;
1982 ModestTnyFolderRules rules;
1984 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1985 g_return_if_fail (TNY_IS_FOLDER (folder));
1987 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1989 /* Check folder rules */
1990 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1991 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1992 /* Set status failed and set an error */
1993 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1994 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1995 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1996 _("mail_in_ui_folder_delete_error"));
2000 /* Get the account */
2001 priv->account = modest_tny_folder_get_account (folder);
2002 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2004 /* Delete folder or move to trash */
2005 if (remove_to_trash) {
2006 TnyFolder *trash_folder = NULL;
2007 trash_folder = modest_tny_account_get_special_folder (priv->account,
2008 TNY_FOLDER_TYPE_TRASH);
2009 /* TODO: error_handling */
2011 modest_mail_operation_notify_start (self);
2012 modest_mail_operation_xfer_folder (self, folder,
2013 TNY_FOLDER_STORE (trash_folder),
2015 g_object_unref (trash_folder);
2017 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2020 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2022 modest_mail_operation_notify_start (self);
2023 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2024 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2027 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2029 g_object_unref (parent);
2031 g_warning ("%s: could not get parent folder", __FUNCTION__);
2035 /* Notify about operation end */
2036 modest_mail_operation_notify_end (self);
2040 transfer_folder_status_cb (GObject *obj,
2044 ModestMailOperation *self;
2045 ModestMailOperationPrivate *priv;
2046 ModestMailOperationState *state;
2047 XFerFolderAsyncHelper *helper;
2049 g_return_if_fail (status != NULL);
2051 /* Show only the status information we want */
2052 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2055 helper = (XFerFolderAsyncHelper *) user_data;
2056 g_return_if_fail (helper != NULL);
2058 self = helper->mail_op;
2059 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2061 priv->done = status->position;
2062 priv->total = status->of_total;
2064 state = modest_mail_operation_clone_state (self);
2066 /* This is not a GDK lock because we are a Tinymail callback
2067 * which is already GDK locked by Tinymail */
2069 /* no gdk_threads_enter (), CHECKED */
2071 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2073 /* no gdk_threads_leave (), CHECKED */
2075 g_slice_free (ModestMailOperationState, state);
2080 transfer_folder_cb (TnyFolder *folder,
2082 TnyFolderStore *into,
2083 TnyFolder *new_folder,
2087 XFerFolderAsyncHelper *helper;
2088 ModestMailOperation *self = NULL;
2089 ModestMailOperationPrivate *priv = NULL;
2091 helper = (XFerFolderAsyncHelper *) user_data;
2092 g_return_if_fail (helper != NULL);
2094 self = helper->mail_op;
2095 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2098 priv->error = g_error_copy (err);
2100 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2101 } else if (cancelled) {
2102 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2103 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2104 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2105 _("Transference of %s was cancelled."),
2106 tny_folder_get_name (folder));
2109 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2112 /* Notify about operation end */
2113 modest_mail_operation_notify_end (self);
2115 /* If user defined callback function was defined, call it */
2116 if (helper->user_callback) {
2118 /* This is not a GDK lock because we are a Tinymail callback
2119 * which is already GDK locked by Tinymail */
2121 /* no gdk_threads_enter (), CHECKED */
2122 helper->user_callback (self, new_folder, helper->user_data);
2123 /* no gdk_threads_leave () , CHECKED */
2127 g_object_unref (helper->mail_op);
2128 g_slice_free (XFerFolderAsyncHelper, helper);
2133 * This function checks if the new name is a valid name for our local
2134 * folders account. The new name could not be the same than then name
2135 * of any of the mandatory local folders
2137 * We can not rely on tinymail because tinymail does not check the
2138 * name of the virtual folders that the account could have in the case
2139 * that we're doing a rename (because it directly calls Camel which
2140 * knows nothing about our virtual folders).
2142 * In the case of an actual copy/move (i.e. move/copy a folder between
2143 * accounts) tinymail uses the tny_folder_store_create_account which
2144 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2145 * checks the new name of the folder, so this call in that case
2146 * wouldn't be needed. *But* NOTE that if tinymail changes its
2147 * implementation (if folder transfers within the same account is no
2148 * longer implemented as a rename) this call will allow Modest to work
2151 * If the new name is not valid, this function will set the status to
2152 * failed and will set also an error in the mail operation
2155 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2156 TnyFolderStore *into,
2157 const gchar *new_name)
2159 if (TNY_IS_ACCOUNT (into) &&
2160 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2161 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2163 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2164 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2165 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2166 _CS("ckdg_ib_folder_already_exists"));
2173 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2175 TnyFolderStore *parent,
2176 gboolean delete_original,
2177 XferFolderAsyncUserCallback user_callback,
2180 ModestMailOperationPrivate *priv = NULL;
2181 ModestTnyFolderRules parent_rules = 0, rules;
2182 XFerFolderAsyncHelper *helper = NULL;
2183 const gchar *folder_name = NULL;
2184 const gchar *error_msg;
2186 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2187 g_return_if_fail (TNY_IS_FOLDER (folder));
2188 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2191 folder_name = tny_folder_get_name (folder);
2193 /* Set the error msg */
2194 error_msg = _("mail_in_ui_folder_move_target_error");
2196 /* Get account and set it into mail_operation */
2197 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2198 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2199 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2201 /* Get folder rules */
2202 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2203 if (TNY_IS_FOLDER (parent))
2204 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2206 /* Apply operation constraints */
2207 if ((gpointer) parent == (gpointer) folder ||
2208 (!TNY_IS_FOLDER_STORE (parent)) ||
2209 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2212 } else if (TNY_IS_FOLDER (parent) &&
2213 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2217 } else if (TNY_IS_FOLDER (parent) &&
2218 TNY_IS_FOLDER_STORE (folder) &&
2219 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2220 TNY_FOLDER_STORE (folder))) {
2221 /* Do not move a parent into a child */
2223 } else if (TNY_IS_FOLDER_STORE (parent) &&
2224 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2225 /* Check that the new folder name is not used by any
2228 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2229 /* Check that the new folder name is not used by any
2230 special local folder */
2233 /* Create the helper */
2234 helper = g_slice_new0 (XFerFolderAsyncHelper);
2235 helper->mail_op = g_object_ref (self);
2236 helper->user_callback = user_callback;
2237 helper->user_data = user_data;
2239 /* Move/Copy folder */
2240 modest_mail_operation_notify_start (self);
2241 tny_folder_copy_async (folder,
2243 tny_folder_get_name (folder),
2246 transfer_folder_status_cb,
2252 /* Set status failed and set an error */
2253 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2254 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2255 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2258 /* Call the user callback if exists */
2260 user_callback (self, NULL, user_data);
2262 /* Notify the queue */
2263 modest_mail_operation_notify_end (self);
2267 modest_mail_operation_rename_folder (ModestMailOperation *self,
2270 XferFolderAsyncUserCallback user_callback,
2273 ModestMailOperationPrivate *priv;
2274 ModestTnyFolderRules rules;
2275 XFerFolderAsyncHelper *helper;
2277 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2278 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2279 g_return_if_fail (name);
2281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2283 /* Get account and set it into mail_operation */
2284 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2285 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2287 /* Check folder rules */
2288 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2289 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2291 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2294 TnyFolderStore *into;
2296 into = tny_folder_get_folder_store (folder);
2298 /* Check that the new folder name is not used by any
2299 special local folder */
2300 if (new_name_valid_if_local_account (priv, into, name)) {
2301 /* Create the helper */
2302 helper = g_slice_new0 (XFerFolderAsyncHelper);
2303 helper->mail_op = g_object_ref(self);
2304 helper->user_callback = user_callback;
2305 helper->user_data = user_data;
2307 /* Rename. Camel handles folder subscription/unsubscription */
2308 modest_mail_operation_notify_start (self);
2309 tny_folder_copy_async (folder, into, name, TRUE,
2311 transfer_folder_status_cb,
2313 g_object_unref (into);
2315 g_object_unref (into);
2322 /* Set status failed and set an error */
2323 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2324 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2325 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2326 _("FIXME: unable to rename"));
2329 user_callback (self, NULL, user_data);
2331 /* Notify about operation end */
2332 modest_mail_operation_notify_end (self);
2335 /* ******************************************************************* */
2336 /* ************************** MSG ACTIONS ************************* */
2337 /* ******************************************************************* */
2340 modest_mail_operation_get_msg (ModestMailOperation *self,
2342 gboolean progress_feedback,
2343 GetMsgAsyncUserCallback user_callback,
2346 GetMsgInfo *helper = NULL;
2348 ModestMailOperationPrivate *priv;
2350 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2351 g_return_if_fail (TNY_IS_HEADER (header));
2353 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2354 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2358 /* Check memory low */
2359 if (_check_memory_low (self)) {
2361 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2362 modest_mail_operation_notify_end (self);
2366 /* Get account and set it into mail_operation */
2367 folder = tny_header_get_folder (header);
2368 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2370 /* Check for cached messages */
2371 if (progress_feedback) {
2372 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2373 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2375 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2377 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2380 /* Create the helper */
2381 helper = g_slice_new0 (GetMsgInfo);
2382 helper->header = g_object_ref (header);
2383 helper->mail_op = g_object_ref (self);
2384 helper->user_callback = user_callback;
2385 helper->user_data = user_data;
2386 helper->destroy_notify = NULL;
2387 helper->last_total_bytes = 0;
2388 helper->sum_total_bytes = 0;
2389 helper->total_bytes = tny_header_get_message_size (header);
2390 helper->more_msgs = NULL;
2392 modest_mail_operation_notify_start (self);
2394 /* notify about the start of the operation */
2395 ModestMailOperationState *state;
2396 state = modest_mail_operation_clone_state (self);
2399 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2401 g_slice_free (ModestMailOperationState, state);
2403 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2405 g_object_unref (G_OBJECT (folder));
2409 get_msg_status_cb (GObject *obj,
2413 GetMsgInfo *helper = NULL;
2415 g_return_if_fail (status != NULL);
2417 /* Show only the status information we want */
2418 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2421 helper = (GetMsgInfo *) user_data;
2422 g_return_if_fail (helper != NULL);
2424 /* Notify progress */
2425 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2426 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2430 get_msg_async_cb (TnyFolder *folder,
2436 GetMsgInfo *info = NULL;
2437 ModestMailOperationPrivate *priv = NULL;
2440 info = (GetMsgInfo *) user_data;
2442 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2445 if (info->more_msgs) {
2446 tny_iterator_next (info->more_msgs);
2447 finished = (tny_iterator_is_done (info->more_msgs));
2449 finished = (priv->done == priv->total) ? TRUE : FALSE;
2452 /* If canceled by the user, ignore the error given by Tinymail */
2456 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2458 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2460 priv->error = g_error_copy ((const GError *) err);
2461 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2464 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2465 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2468 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2469 /* Set the success status before calling the user callback */
2470 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2474 /* Call the user callback */
2475 if (info->user_callback)
2476 info->user_callback (info->mail_op, info->header, canceled,
2477 msg, err, info->user_data);
2479 /* Notify about operation end if this is the last callback */
2481 /* Free user data */
2482 if (info->destroy_notify)
2483 info->destroy_notify (info->user_data);
2485 /* Notify about operation end */
2486 modest_mail_operation_notify_end (info->mail_op);
2489 if (info->more_msgs)
2490 g_object_unref (info->more_msgs);
2491 g_object_unref (info->header);
2492 g_object_unref (info->mail_op);
2493 g_slice_free (GetMsgInfo, info);
2494 } else if (info->more_msgs) {
2495 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2496 TnyFolder *folder = tny_header_get_folder (header);
2498 g_object_unref (info->header);
2499 info->header = g_object_ref (header);
2501 /* Retrieve the next message */
2502 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2504 g_object_unref (header);
2505 g_object_unref (folder);
2507 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2512 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2513 TnyList *header_list,
2514 GetMsgAsyncUserCallback user_callback,
2516 GDestroyNotify notify)
2518 ModestMailOperationPrivate *priv = NULL;
2520 TnyIterator *iter = NULL;
2521 gboolean has_uncached_messages;
2523 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2525 /* Init mail operation */
2526 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2527 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2529 priv->total = tny_list_get_length(header_list);
2531 /* Check memory low */
2532 if (_check_memory_low (self)) {
2533 if (user_callback) {
2534 TnyHeader *header = NULL;
2537 if (tny_list_get_length (header_list) > 0) {
2538 iter = tny_list_create_iterator (header_list);
2539 header = (TnyHeader *) tny_iterator_get_current (iter);
2540 g_object_unref (iter);
2542 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2544 g_object_unref (header);
2548 /* Notify about operation end */
2549 modest_mail_operation_notify_end (self);
2553 /* Check uncached messages */
2554 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2555 !has_uncached_messages && !tny_iterator_is_done (iter);
2556 tny_iterator_next (iter)) {
2559 header = (TnyHeader *) tny_iterator_get_current (iter);
2560 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2561 has_uncached_messages = TRUE;
2562 g_object_unref (header);
2564 g_object_unref (iter);
2565 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2567 /* Get account and set it into mail_operation */
2568 if (tny_list_get_length (header_list) >= 1) {
2569 TnyIterator *iterator = tny_list_create_iterator (header_list);
2570 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2572 TnyFolder *folder = tny_header_get_folder (header);
2574 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2575 g_object_unref (folder);
2577 g_object_unref (header);
2579 g_object_unref (iterator);
2582 msg_list_size = compute_message_list_size (header_list, 0);
2584 modest_mail_operation_notify_start (self);
2585 iter = tny_list_create_iterator (header_list);
2586 if (!tny_iterator_is_done (iter)) {
2587 /* notify about the start of the operation */
2588 ModestMailOperationState *state;
2589 state = modest_mail_operation_clone_state (self);
2592 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2595 GetMsgInfo *msg_info = NULL;
2596 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2597 TnyFolder *folder = tny_header_get_folder (header);
2599 /* Create the message info */
2600 msg_info = g_slice_new0 (GetMsgInfo);
2601 msg_info->mail_op = g_object_ref (self);
2602 msg_info->header = g_object_ref (header);
2603 msg_info->more_msgs = g_object_ref (iter);
2604 msg_info->user_callback = user_callback;
2605 msg_info->user_data = user_data;
2606 msg_info->destroy_notify = notify;
2607 msg_info->last_total_bytes = 0;
2608 msg_info->sum_total_bytes = 0;
2609 msg_info->total_bytes = msg_list_size;
2611 /* The callback will call it per each header */
2612 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2614 /* Free and go on */
2615 g_object_unref (header);
2616 g_object_unref (folder);
2617 g_slice_free (ModestMailOperationState, state);
2619 g_object_unref (iter);
2624 remove_msgs_async_cb (TnyFolder *folder,
2629 gboolean expunge, leave_on_server;
2630 const gchar *account_name;
2631 TnyAccount *account;
2632 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2633 ModestMailOperation *self;
2634 ModestMailOperationPrivate *priv;
2635 ModestProtocolRegistry *protocol_registry;
2637 self = (ModestMailOperation *) user_data;
2638 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2639 protocol_registry = modest_runtime_get_protocol_registry ();
2641 if (canceled || err) {
2642 /* If canceled by the user, ignore the error given by Tinymail */
2644 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2646 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2647 priv->error = g_error_copy ((const GError *) err);
2648 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2651 modest_mail_operation_notify_end (self);
2652 g_object_unref (self);
2656 account = tny_folder_get_account (folder);
2657 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2659 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2661 account_proto = modest_tny_account_get_protocol_type (account);
2662 g_object_unref (account);
2664 if (( (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) && !leave_on_server) ||
2665 modest_tny_folder_is_remote_folder (folder) == FALSE))
2671 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2676 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2678 gboolean remove_to_trash /*ignored*/)
2680 TnyFolder *folder = NULL;
2681 ModestMailOperationPrivate *priv;
2682 TnyIterator *iter = NULL;
2683 TnyHeader *header = NULL;
2684 TnyList *remove_headers = NULL;
2685 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2687 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2688 g_return_if_fail (TNY_IS_LIST (headers));
2690 if (remove_to_trash)
2691 g_warning ("remove to trash is not implemented");
2693 if (tny_list_get_length(headers) == 0) {
2694 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2695 goto cleanup; /* nothing to do */
2698 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2699 remove_headers = g_object_ref(headers);
2701 /* Get folder from first header and sync it */
2702 iter = tny_list_create_iterator (headers);
2703 header = TNY_HEADER (tny_iterator_get_current (iter));
2705 folder = tny_header_get_folder (header);
2706 if (!TNY_IS_FOLDER(folder)) {
2707 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2711 /* Don't remove messages that are being sent */
2712 if (modest_tny_folder_is_local_folder (folder)) {
2713 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2715 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2716 TnyTransportAccount *traccount = NULL;
2717 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2718 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2720 ModestTnySendQueueStatus status;
2721 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2723 if (TNY_IS_SEND_QUEUE (send_queue)) {
2724 TnyIterator *iter = tny_list_create_iterator(headers);
2725 g_object_unref(remove_headers);
2726 remove_headers = TNY_LIST(tny_simple_list_new());
2727 while (!tny_iterator_is_done(iter)) {
2729 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2730 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2731 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2732 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2733 tny_list_append(remove_headers, G_OBJECT(hdr));
2735 g_object_unref(hdr);
2737 tny_iterator_next(iter);
2739 g_object_unref(iter);
2741 g_object_unref(traccount);
2745 /* Get account and set it into mail_operation */
2746 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2747 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2748 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2750 /* remove message from folder */
2751 modest_mail_operation_notify_start (self);
2752 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2753 NULL, g_object_ref (self));
2757 g_object_unref (remove_headers);
2759 g_object_unref (header);
2761 g_object_unref (iter);
2763 g_object_unref (folder);
2767 notify_progress_of_multiple_messages (ModestMailOperation *self,
2769 gint *last_total_bytes,
2770 gint *sum_total_bytes,
2772 gboolean increment_done)
2774 ModestMailOperationPrivate *priv;
2775 ModestMailOperationState *state;
2776 gboolean is_num_bytes = FALSE;
2778 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2780 /* We know that tinymail sends us information about
2781 * transferred bytes with this particular message
2783 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2784 * I just added the 'if' so we don't get runtime warning)
2786 if (status->message)
2787 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2789 state = modest_mail_operation_clone_state (self);
2790 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2791 /* We know that we're in a different message when the
2792 total number of bytes to transfer is different. Of
2793 course it could fail if we're transferring messages
2794 of the same size, but this is a workarround */
2795 if (status->of_total != *last_total_bytes) {
2796 /* We need to increment the done when there is
2797 no information about each individual
2798 message, we need to do this in message
2799 transfers, and we don't do it for getting
2803 *sum_total_bytes += *last_total_bytes;
2804 *last_total_bytes = status->of_total;
2806 state->bytes_done += status->position + *sum_total_bytes;
2807 state->bytes_total = total_bytes;
2809 /* Notify the status change. Only notify about changes
2810 referred to bytes */
2811 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2815 g_slice_free (ModestMailOperationState, state);
2819 transfer_msgs_status_cb (GObject *obj,
2823 XFerMsgsAsyncHelper *helper;
2825 g_return_if_fail (status != NULL);
2827 /* Show only the status information we want */
2828 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2831 helper = (XFerMsgsAsyncHelper *) user_data;
2832 g_return_if_fail (helper != NULL);
2834 /* Notify progress */
2835 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2836 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2840 transfer_msgs_sync_folder_cb (TnyFolder *self,
2845 XFerMsgsAsyncHelper *helper;
2846 /* We don't care here about the results of the
2848 helper = (XFerMsgsAsyncHelper *) user_data;
2850 /* Notify about operation end */
2851 modest_mail_operation_notify_end (helper->mail_op);
2853 /* If user defined callback function was defined, call it */
2854 if (helper->user_callback)
2855 helper->user_callback (helper->mail_op, helper->user_data);
2858 if (helper->more_msgs)
2859 g_object_unref (helper->more_msgs);
2860 if (helper->headers)
2861 g_object_unref (helper->headers);
2862 if (helper->dest_folder)
2863 g_object_unref (helper->dest_folder);
2864 if (helper->mail_op)
2865 g_object_unref (helper->mail_op);
2866 g_slice_free (XFerMsgsAsyncHelper, helper);
2870 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2872 XFerMsgsAsyncHelper *helper;
2873 ModestMailOperation *self;
2874 ModestMailOperationPrivate *priv;
2875 gboolean finished = TRUE;
2877 helper = (XFerMsgsAsyncHelper *) user_data;
2878 self = helper->mail_op;
2880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2883 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2885 priv->error = g_error_copy (err);
2887 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2888 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2889 if (helper->more_msgs) {
2890 /* We'll transfer the next message in the list */
2891 tny_iterator_next (helper->more_msgs);
2892 if (!tny_iterator_is_done (helper->more_msgs)) {
2893 GObject *next_header;
2894 g_object_unref (helper->headers);
2895 helper->headers = tny_simple_list_new ();
2896 next_header = tny_iterator_get_current (helper->more_msgs);
2897 tny_list_append (helper->headers, next_header);
2898 g_object_unref (next_header);
2904 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2909 /* Synchronize the source folder contents. This should
2910 be done by tinymail but the camel_folder_sync it's
2911 actually disabled in transfer_msgs_thread_clean
2912 because it's supposed to cause hangs */
2913 tny_folder_sync_async (folder, helper->delete,
2914 transfer_msgs_sync_folder_cb,
2917 /* Transfer more messages */
2918 tny_folder_transfer_msgs_async (folder,
2920 helper->dest_folder,
2923 transfer_msgs_status_cb,
2928 /* Computes the size of the messages the headers in the list belongs
2929 to. If num_elements is different from 0 then it only takes into
2930 account the first num_elements for the calculation */
2932 compute_message_list_size (TnyList *headers,
2936 guint size = 0, element = 0;
2938 /* If num_elements is not valid then take all into account */
2939 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2940 num_elements = tny_list_get_length (headers);
2942 iter = tny_list_create_iterator (headers);
2943 while (!tny_iterator_is_done (iter) && element < num_elements) {
2944 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2945 size += tny_header_get_message_size (header);
2946 g_object_unref (header);
2947 tny_iterator_next (iter);
2950 g_object_unref (iter);
2956 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2959 gboolean delete_original,
2960 XferMsgsAsyncUserCallback user_callback,
2963 ModestMailOperationPrivate *priv = NULL;
2964 TnyIterator *iter = NULL;
2965 TnyFolder *src_folder = NULL;
2966 XFerMsgsAsyncHelper *helper = NULL;
2967 TnyHeader *header = NULL;
2968 ModestTnyFolderRules rules = 0;
2969 TnyAccount *dst_account = NULL;
2970 gboolean leave_on_server;
2971 ModestMailOperationState *state;
2972 ModestProtocolRegistry *protocol_registry;
2973 ModestProtocolType account_protocol;
2975 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2976 g_return_if_fail (headers && TNY_IS_LIST (headers));
2977 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2980 protocol_registry = modest_runtime_get_protocol_registry ();
2982 priv->total = tny_list_get_length (headers);
2984 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2985 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2987 /* Apply folder rules */
2988 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2989 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2990 /* Set status failed and set an error */
2991 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2992 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2993 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2994 _CS("ckct_ib_unable_to_paste_here"));
2995 /* Notify the queue */
2996 modest_mail_operation_notify_end (self);
3000 /* Get source folder */
3001 iter = tny_list_create_iterator (headers);
3002 header = TNY_HEADER (tny_iterator_get_current (iter));
3004 src_folder = tny_header_get_folder (header);
3005 g_object_unref (header);
3007 g_object_unref (iter);
3009 if (src_folder == NULL) {
3010 /* Notify the queue */
3011 modest_mail_operation_notify_end (self);
3013 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3018 /* Check folder source and destination */
3019 if (src_folder == folder) {
3020 /* Set status failed and set an error */
3021 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3022 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3023 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3024 _("mail_in_ui_folder_copy_target_error"));
3026 /* Notify the queue */
3027 modest_mail_operation_notify_end (self);
3030 g_object_unref (src_folder);
3034 /* Create the helper */
3035 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3036 helper->mail_op = g_object_ref(self);
3037 helper->dest_folder = g_object_ref(folder);
3038 helper->user_callback = user_callback;
3039 helper->user_data = user_data;
3040 helper->last_total_bytes = 0;
3041 helper->sum_total_bytes = 0;
3042 helper->total_bytes = compute_message_list_size (headers, 0);
3044 /* Get account and set it into mail_operation */
3045 priv->account = modest_tny_folder_get_account (src_folder);
3046 dst_account = modest_tny_folder_get_account (folder);
3048 if (priv->account == dst_account) {
3049 /* Transfer all messages at once using the fast
3050 * method. Note that depending on the server this
3051 * might not be that fast, and might not be
3052 * user-cancellable either */
3053 helper->headers = g_object_ref (headers);
3054 helper->more_msgs = NULL;
3056 /* Transfer messages one by one so the user can cancel
3059 helper->headers = tny_simple_list_new ();
3060 helper->more_msgs = tny_list_create_iterator (headers);
3061 hdr = tny_iterator_get_current (helper->more_msgs);
3062 tny_list_append (helper->headers, hdr);
3063 g_object_unref (hdr);
3066 /* If leave_on_server is set to TRUE then don't use
3067 delete_original, we always pass FALSE. This is because
3068 otherwise tinymail will try to sync the source folder and
3069 this could cause an error if we're offline while
3070 transferring an already downloaded message from a POP
3072 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3073 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3074 const gchar *account_name;
3076 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3077 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3080 leave_on_server = FALSE;
3083 /* Do not delete messages if leave on server is TRUE */
3084 helper->delete = (leave_on_server) ? FALSE : delete_original;
3086 modest_mail_operation_notify_start (self);
3088 /* Start notifying progress */
3089 state = modest_mail_operation_clone_state (self);
3092 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3093 g_slice_free (ModestMailOperationState, state);
3095 tny_folder_transfer_msgs_async (src_folder,
3100 transfer_msgs_status_cb,
3102 g_object_unref (src_folder);
3103 g_object_unref (dst_account);
3108 on_refresh_folder (TnyFolder *folder,
3113 RefreshAsyncHelper *helper = NULL;
3114 ModestMailOperation *self = NULL;
3115 ModestMailOperationPrivate *priv = NULL;
3117 helper = (RefreshAsyncHelper *) user_data;
3118 self = helper->mail_op;
3119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3121 g_return_if_fail(priv!=NULL);
3124 priv->error = g_error_copy (error);
3125 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3130 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3131 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3132 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3133 _("Error trying to refresh the contents of %s"),
3134 tny_folder_get_name (folder));
3138 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3141 /* Call user defined callback, if it exists */
3142 if (helper->user_callback) {
3144 /* This is not a GDK lock because we are a Tinymail callback and
3145 * Tinymail already acquires the Gdk lock */
3146 helper->user_callback (self, folder, helper->user_data);
3150 g_slice_free (RefreshAsyncHelper, helper);
3152 /* Notify about operation end */
3153 modest_mail_operation_notify_end (self);
3154 g_object_unref(self);
3158 on_refresh_folder_status_update (GObject *obj,
3162 RefreshAsyncHelper *helper = NULL;
3163 ModestMailOperation *self = NULL;
3164 ModestMailOperationPrivate *priv = NULL;
3165 ModestMailOperationState *state;
3167 g_return_if_fail (user_data != NULL);
3168 g_return_if_fail (status != NULL);
3170 /* Show only the status information we want */
3171 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3174 helper = (RefreshAsyncHelper *) user_data;
3175 self = helper->mail_op;
3176 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3180 priv->done = status->position;
3181 priv->total = status->of_total;
3183 state = modest_mail_operation_clone_state (self);
3185 /* This is not a GDK lock because we are a Tinymail callback and
3186 * Tinymail already acquires the Gdk lock */
3187 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3189 g_slice_free (ModestMailOperationState, state);
3193 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3195 RefreshAsyncUserCallback user_callback,
3198 ModestMailOperationPrivate *priv = NULL;
3199 RefreshAsyncHelper *helper = NULL;
3201 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3203 /* Check memory low */
3204 if (_check_memory_low (self)) {
3206 user_callback (self, folder, user_data);
3207 /* Notify about operation end */
3208 modest_mail_operation_notify_end (self);
3212 /* Get account and set it into mail_operation */
3213 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3214 priv->account = modest_tny_folder_get_account (folder);
3215 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3217 /* Create the helper */
3218 helper = g_slice_new0 (RefreshAsyncHelper);
3219 helper->mail_op = g_object_ref(self);
3220 helper->user_callback = user_callback;
3221 helper->user_data = user_data;
3223 modest_mail_operation_notify_start (self);
3225 /* notify that the operation was started */
3226 ModestMailOperationState *state;
3227 state = modest_mail_operation_clone_state (self);
3230 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3232 g_slice_free (ModestMailOperationState, state);
3234 tny_folder_refresh_async (folder,
3236 on_refresh_folder_status_update,
3241 run_queue_stop (ModestTnySendQueue *queue,
3242 ModestMailOperation *self)
3244 ModestMailOperationPrivate *priv;
3246 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3247 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3248 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3250 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3252 modest_mail_operation_notify_end (self);
3253 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3254 g_object_unref (self);
3258 modest_mail_operation_run_queue (ModestMailOperation *self,
3259 ModestTnySendQueue *queue)
3261 ModestMailOperationPrivate *priv;
3263 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3264 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3265 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3267 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3268 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3269 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3271 modest_mail_operation_notify_start (self);
3272 g_object_ref (self);
3273 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3277 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3279 ModestMailOperation *self = (ModestMailOperation *) userdata;
3280 ModestMailOperationPrivate *priv;
3282 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3283 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3286 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3288 modest_mail_operation_notify_end (self);
3289 g_object_unref (self);
3293 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3295 ModestMailOperationPrivate *priv;
3297 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3298 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3299 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3301 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3303 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3304 priv->account = NULL;
3305 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3307 modest_mail_operation_notify_start (self);
3308 g_object_ref (self);
3309 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3313 sync_folder_finish_callback (TnyFolder *self,
3319 ModestMailOperation *mail_op;
3320 ModestMailOperationPrivate *priv;
3322 mail_op = (ModestMailOperation *) user_data;
3323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3325 /* If canceled by the user, ignore the error given by Tinymail */
3327 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3329 /* If the operation was a sync then the status is
3330 failed, but if it's part of another operation then
3331 just set it as finished with errors */
3332 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3333 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3335 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3336 priv->error = g_error_copy ((const GError *) err);
3337 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3339 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3342 modest_mail_operation_notify_end (mail_op);
3343 g_object_unref (mail_op);
3347 modest_mail_operation_sync_folder (ModestMailOperation *self,
3348 TnyFolder *folder, gboolean expunge)
3350 ModestMailOperationPrivate *priv;
3352 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3353 g_return_if_fail (TNY_IS_FOLDER (folder));
3354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3356 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3357 priv->account = modest_tny_folder_get_account (folder);
3358 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3360 modest_mail_operation_notify_start (self);
3361 g_object_ref (self);
3362 tny_folder_sync_async (folder, expunge,
3363 (TnyFolderCallback) sync_folder_finish_callback,
3368 modest_mail_operation_notify_start (ModestMailOperation *self)
3370 ModestMailOperationPrivate *priv = NULL;
3372 g_return_if_fail (self);
3374 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3376 /* Ensure that all the fields are filled correctly */
3377 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3379 /* Notify the observers about the mail operation. We do not
3380 wrapp this emission because we assume that this function is
3381 always called from within the main lock */
3382 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3387 * It's used by the mail operation queue to notify the observers
3388 * attached to that signal that the operation finished. We need to use
3389 * that because tinymail does not give us the progress of a given
3390 * operation when it finishes (it directly calls the operation
3394 modest_mail_operation_notify_end (ModestMailOperation *self)
3396 ModestMailOperationPrivate *priv = NULL;
3398 g_return_if_fail (self);
3400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3402 /* Notify the observers about the mail operation end. We do
3403 not wrapp this emission because we assume that this
3404 function is always called from within the main lock */
3405 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3407 /* Remove the error user data */
3408 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3409 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3413 modest_mail_operation_get_account (ModestMailOperation *self)
3415 ModestMailOperationPrivate *priv = NULL;
3417 g_return_val_if_fail (self, NULL);
3419 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3421 return (priv->account) ? g_object_ref (priv->account) : NULL;
3425 modest_mail_operation_noop (ModestMailOperation *self)
3427 ModestMailOperationPrivate *priv = NULL;
3429 g_return_if_fail (self);
3431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3432 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3433 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3437 /* This mail operation does nothing actually */
3438 modest_mail_operation_notify_start (self);
3439 modest_mail_operation_notify_end (self);
3444 modest_mail_operation_to_string (ModestMailOperation *self)
3446 const gchar *type, *status, *account_id;
3447 ModestMailOperationPrivate *priv = NULL;
3449 g_return_val_if_fail (self, NULL);
3451 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3453 /* new operations don't have anything interesting */
3454 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3455 return g_strdup_printf ("%p <new operation>", self);
3457 switch (priv->op_type) {
3458 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3459 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3460 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3461 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3462 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3463 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3464 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3465 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3466 default: type = "UNEXPECTED"; break;
3469 switch (priv->status) {
3470 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3471 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3472 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3473 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3474 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3475 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3476 default: status= "UNEXPECTED"; break;
3479 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3481 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3482 priv->done, priv->total,
3483 priv->error && priv->error->message ? priv->error->message : "");
3487 * Once the mail operations were objects this will be no longer
3488 * needed. I don't like it, but we need it for the moment
3491 _check_memory_low (ModestMailOperation *mail_op)
3493 if (modest_platform_check_memory_low (NULL, FALSE)) {
3494 ModestMailOperationPrivate *priv;
3496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3497 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3498 g_set_error (&(priv->error),
3499 MODEST_MAIL_OPERATION_ERROR,
3500 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3501 "Not enough memory to complete the operation");