1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers, guint num_elements);
100 static int compare_headers_by_date (gconstpointer a,
103 static void sync_folder_finish_callback (TnyFolder *self,
108 static gboolean _check_memory_low (ModestMailOperation *mail_op);
110 /* Helpers for the update account operation (send & receive)*/
113 ModestMailOperation *mail_op;
115 UpdateAccountCallback callback;
120 TnyFolderObserver *inbox_observer;
121 RetrieveAllCallback retrieve_all_cb;
122 gboolean interactive;
126 static void destroy_update_account_info (UpdateAccountInfo *info);
128 static void update_account_send_mail (UpdateAccountInfo *info);
130 static void update_account_get_msg_async_cb (TnyFolder *folder,
136 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
137 TnyList *new_headers);
139 enum _ModestMailOperationSignals
141 PROGRESS_CHANGED_SIGNAL,
142 OPERATION_STARTED_SIGNAL,
143 OPERATION_FINISHED_SIGNAL,
147 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
148 struct _ModestMailOperationPrivate {
154 ErrorCheckingUserCallback error_checking;
155 gpointer error_checking_user_data;
156 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
157 ModestMailOperationStatus status;
158 ModestMailOperationTypeOperation op_type;
161 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
162 MODEST_TYPE_MAIL_OPERATION, \
163 ModestMailOperationPrivate))
165 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
166 priv->status = new_status;\
171 GetMsgAsyncUserCallback user_callback;
173 TnyIterator *more_msgs;
175 ModestMailOperation *mail_op;
176 GDestroyNotify destroy_notify;
177 gint last_total_bytes;
178 gint sum_total_bytes;
182 typedef struct _RefreshAsyncHelper {
183 ModestMailOperation *mail_op;
184 RefreshAsyncUserCallback user_callback;
186 } RefreshAsyncHelper;
188 typedef struct _XFerMsgsAsyncHelper
190 ModestMailOperation *mail_op;
192 TnyIterator *more_msgs;
193 TnyFolder *dest_folder;
194 XferMsgsAsyncUserCallback user_callback;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 } XFerMsgsAsyncHelper;
202 typedef struct _XFerFolderAsyncHelper
204 ModestMailOperation *mail_op;
205 XferFolderAsyncUserCallback user_callback;
207 } XFerFolderAsyncHelper;
209 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
213 static void modest_mail_operation_create_msg (ModestMailOperation *self,
214 const gchar *from, const gchar *to,
215 const gchar *cc, const gchar *bcc,
216 const gchar *subject, const gchar *plain_body,
217 const gchar *html_body, const GList *attachments_list,
218 const GList *images_list,
219 TnyHeaderFlags priority_flags,
220 ModestMailOperationCreateMsgCallback callback,
223 static gboolean idle_notify_queue (gpointer data);
226 ModestMailOperation *mail_op;
234 GList *attachments_list;
236 TnyHeaderFlags priority_flags;
237 ModestMailOperationCreateMsgCallback callback;
243 ModestMailOperation *mail_op;
245 ModestMailOperationCreateMsgCallback callback;
250 static GObjectClass *parent_class = NULL;
252 static guint signals[NUM_SIGNALS] = {0};
255 modest_mail_operation_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMailOperationClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_mail_operation_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMailOperation),
268 (GInstanceInitFunc) modest_mail_operation_init,
271 my_type = g_type_register_static (G_TYPE_OBJECT,
272 "ModestMailOperation",
279 modest_mail_operation_class_init (ModestMailOperationClass *klass)
281 GObjectClass *gobject_class;
282 gobject_class = (GObjectClass*) klass;
284 parent_class = g_type_class_peek_parent (klass);
285 gobject_class->finalize = modest_mail_operation_finalize;
287 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
290 * ModestMailOperation::progress-changed
291 * @self: the #MailOperation that emits the signal
292 * @user_data: user data set when the signal handler was connected
294 * Emitted when the progress of a mail operation changes
296 signals[PROGRESS_CHANGED_SIGNAL] =
297 g_signal_new ("progress-changed",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
302 g_cclosure_marshal_VOID__POINTER,
303 G_TYPE_NONE, 1, G_TYPE_POINTER);
307 * This signal is issued whenever a mail operation starts, and
308 * starts mean when the tinymail operation is issued. This
309 * means that it could happen that something wrong happens and
310 * the tinymail function is never called. In this situation a
311 * operation-finished will be issued without any
314 signals[OPERATION_STARTED_SIGNAL] =
315 g_signal_new ("operation-started",
316 G_TYPE_FROM_CLASS (gobject_class),
318 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
320 g_cclosure_marshal_VOID__VOID,
325 * This signal is issued whenever a mail operation
326 * finishes. Note that this signal could be issued without any
327 * previous "operation-started" signal, because this last one
328 * is only issued when the tinymail operation is successfully
331 signals[OPERATION_FINISHED_SIGNAL] =
332 g_signal_new ("operation-finished",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
337 g_cclosure_marshal_VOID__VOID,
342 modest_mail_operation_init (ModestMailOperation *obj)
344 ModestMailOperationPrivate *priv;
346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
348 priv->account = NULL;
349 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
355 priv->error_checking = NULL;
356 priv->error_checking_user_data = NULL;
360 modest_mail_operation_finalize (GObject *obj)
362 ModestMailOperationPrivate *priv;
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
369 g_error_free (priv->error);
373 g_object_unref (priv->source);
377 g_object_unref (priv->account);
378 priv->account = NULL;
382 G_OBJECT_CLASS(parent_class)->finalize (obj);
386 modest_mail_operation_new (GObject *source)
388 ModestMailOperation *obj;
389 ModestMailOperationPrivate *priv;
391 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
395 priv->source = g_object_ref(source);
401 modest_mail_operation_new_with_error_handling (GObject *source,
402 ErrorCheckingUserCallback error_handler,
404 ErrorCheckingUserDataDestroyer error_handler_destroyer)
406 ModestMailOperation *obj;
407 ModestMailOperationPrivate *priv;
409 obj = modest_mail_operation_new (source);
410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 g_return_val_if_fail (error_handler != NULL, obj);
413 priv->error_checking = error_handler;
414 priv->error_checking_user_data = user_data;
415 priv->error_checking_user_data_destroyer = error_handler_destroyer;
421 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
423 ModestMailOperationPrivate *priv;
425 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
428 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
430 /* Call the user callback */
431 if (priv->error_checking != NULL)
432 priv->error_checking (self, priv->error_checking_user_data);
436 ModestMailOperationTypeOperation
437 modest_mail_operation_get_type_operation (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
442 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
446 return priv->op_type;
450 modest_mail_operation_is_mine (ModestMailOperation *self,
453 ModestMailOperationPrivate *priv;
455 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 if (priv->source == NULL) return FALSE;
461 return priv->source == me;
465 modest_mail_operation_get_source (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
474 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
478 return (priv->source) ? g_object_ref (priv->source) : NULL;
481 ModestMailOperationStatus
482 modest_mail_operation_get_status (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
487 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
488 MODEST_MAIL_OPERATION_STATUS_INVALID);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
492 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
493 return MODEST_MAIL_OPERATION_STATUS_INVALID;
500 modest_mail_operation_get_error (ModestMailOperation *self)
502 ModestMailOperationPrivate *priv;
504 g_return_val_if_fail (self, NULL);
505 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
510 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
518 modest_mail_operation_cancel (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
521 gboolean canceled = FALSE;
523 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
528 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
530 /* Cancel the mail operation */
531 g_return_val_if_fail (priv->account, FALSE);
532 tny_account_cancel (priv->account);
534 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
535 ModestTnySendQueue *queue;
536 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
539 /* Cancel the sending of the following next messages */
540 if (TNY_IS_SEND_QUEUE (queue))
541 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
548 modest_mail_operation_get_task_done (ModestMailOperation *self)
550 ModestMailOperationPrivate *priv;
552 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
560 modest_mail_operation_get_task_total (ModestMailOperation *self)
562 ModestMailOperationPrivate *priv;
564 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
572 modest_mail_operation_is_finished (ModestMailOperation *self)
574 ModestMailOperationPrivate *priv;
575 gboolean retval = FALSE;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
582 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
583 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
584 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
585 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
595 * Creates an image of the current state of a mail operation, the
596 * caller must free it
598 static ModestMailOperationState *
599 modest_mail_operation_clone_state (ModestMailOperation *self)
601 ModestMailOperationState *state;
602 ModestMailOperationPrivate *priv;
604 /* FIXME: this should be fixed properly
606 * in some cases, priv was NULL, so checking here to
609 g_return_val_if_fail (self, NULL);
610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
611 g_return_val_if_fail (priv, NULL);
616 state = g_slice_new (ModestMailOperationState);
618 state->status = priv->status;
619 state->op_type = priv->op_type;
620 state->done = priv->done;
621 state->total = priv->total;
622 state->finished = modest_mail_operation_is_finished (self);
623 state->bytes_done = 0;
624 state->bytes_total = 0;
629 /* ******************************************************************* */
630 /* ************************** SEND ACTIONS ************************* */
631 /* ******************************************************************* */
635 ModestMailOperation *mail_op;
640 send_mail_common_cb (gboolean cancelled,
642 SendNewMailHelper *helper)
644 ModestMailOperationPrivate *priv;
645 ModestMailOperation *self;
647 self = helper->mail_op;
648 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
650 if (cancelled || err)
654 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
655 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
656 "Error adding a msg to the send queue\n");
657 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
659 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
664 modest_mail_operation_notify_end (self);
666 g_object_unref (helper->mail_op);
667 g_slice_free (SendNewMailHelper, helper);
671 send_mail_on_sync_async_cb (TnyFolder *self,
676 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
680 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
686 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
690 idle_create_msg_cb (gpointer idle_data)
692 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
694 /* This is a GDK lock because we are an idle callback and
695 * info->callback can contain Gtk+ code */
697 gdk_threads_enter (); /* CHECKED */
698 info->callback (info->mail_op, info->msg, info->userdata);
700 g_object_unref (info->mail_op);
702 g_object_unref (info->msg);
703 g_slice_free (CreateMsgIdleInfo, info);
704 gdk_threads_leave (); /* CHECKED */
710 create_msg_thread (gpointer thread_data)
712 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
713 TnyMsg *new_msg = NULL;
714 ModestMailOperationPrivate *priv;
716 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
717 if (info->html_body == NULL) {
718 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
719 info->bcc, info->subject, info->plain_body,
720 info->attachments_list,
723 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
724 info->bcc, info->subject, info->html_body,
725 info->plain_body, info->attachments_list,
733 /* Set priority flags in message */
734 header = tny_msg_get_header (new_msg);
735 tny_header_set_flag (header, info->priority_flags);
737 /* Set attachment flags in message */
738 if (info->attachments_list != NULL)
739 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
741 g_object_unref (G_OBJECT(header));
743 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
746 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
747 "modest: failed to create a new msg\n");
755 g_free (info->plain_body);
756 g_free (info->html_body);
757 g_free (info->subject);
758 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
759 g_list_free (info->attachments_list);
760 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
761 g_list_free (info->images_list);
763 if (info->callback) {
764 CreateMsgIdleInfo *idle_info;
765 idle_info = g_slice_new0 (CreateMsgIdleInfo);
766 idle_info->mail_op = g_object_ref (info->mail_op);
767 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
768 idle_info->callback = info->callback;
769 idle_info->userdata = info->userdata;
770 g_idle_add (idle_create_msg_cb, idle_info);
772 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
775 g_object_unref (info->mail_op);
776 g_slice_free (CreateMsgInfo, info);
777 if (new_msg) g_object_unref(new_msg);
783 modest_mail_operation_create_msg (ModestMailOperation *self,
784 const gchar *from, const gchar *to,
785 const gchar *cc, const gchar *bcc,
786 const gchar *subject, const gchar *plain_body,
787 const gchar *html_body,
788 const GList *attachments_list,
789 const GList *images_list,
790 TnyHeaderFlags priority_flags,
791 ModestMailOperationCreateMsgCallback callback,
794 CreateMsgInfo *info = NULL;
796 info = g_slice_new0 (CreateMsgInfo);
797 info->mail_op = g_object_ref (self);
799 info->from = g_strdup (from);
800 info->to = g_strdup (to);
801 info->cc = g_strdup (cc);
802 info->bcc = g_strdup (bcc);
803 info->subject = g_strdup (subject);
804 info->plain_body = g_strdup (plain_body);
805 info->html_body = g_strdup (html_body);
806 info->attachments_list = g_list_copy ((GList *) attachments_list);
807 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
808 info->images_list = g_list_copy ((GList *) images_list);
809 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
810 info->priority_flags = priority_flags;
812 info->callback = callback;
813 info->userdata = userdata;
815 g_thread_create (create_msg_thread, info, FALSE, NULL);
820 TnyTransportAccount *transport_account;
825 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
829 TnySendQueue *send_queue = NULL;
830 ModestMailOperationPrivate *priv = NULL;
831 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
832 TnyFolder *draft_folder = NULL;
833 TnyFolder *outbox_folder = NULL;
834 TnyHeader *header = NULL;
836 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
839 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
840 modest_mail_operation_notify_end (self);
844 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
845 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
846 modest_mail_operation_notify_end (self);
850 /* Add message to send queue */
851 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
852 if (!TNY_IS_SEND_QUEUE(send_queue)) {
854 g_error_free (priv->error);
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
859 "modest: could not find send queue for account\n");
860 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
861 modest_mail_operation_notify_end (self);
864 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
865 helper->mail_op = g_object_ref (self);
866 helper->notify = (info->draft_msg == NULL);
868 /* Add the msg to the queue. The callback will free
870 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
872 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
876 if (info->draft_msg != NULL) {
877 TnyList *tmp_headers = NULL;
878 TnyFolder *folder = NULL;
879 TnyFolder *src_folder = NULL;
880 TnyFolderType folder_type;
881 TnyTransportAccount *transport_account = NULL;
882 SendNewMailHelper *helper = NULL;
884 /* To remove the old mail from its source folder, we need to get the
885 * transport account of the original draft message (the transport account
886 * might have been changed by the user) */
887 header = tny_msg_get_header (info->draft_msg);
888 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
889 modest_runtime_get_account_store(), header);
890 if (transport_account == NULL)
891 transport_account = g_object_ref(info->transport_account);
892 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
893 TNY_FOLDER_TYPE_DRAFTS);
894 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
895 TNY_FOLDER_TYPE_OUTBOX);
896 g_object_unref(transport_account);
899 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
901 modest_mail_operation_notify_end (self);
904 if (!outbox_folder) {
905 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
907 modest_mail_operation_notify_end (self);
911 folder = tny_msg_get_folder (info->draft_msg);
912 if (folder == NULL) {
913 modest_mail_operation_notify_end (self);
916 folder_type = modest_tny_folder_guess_folder_type (folder);
918 if (folder_type == TNY_FOLDER_TYPE_INVALID)
919 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
921 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
922 src_folder = outbox_folder;
924 src_folder = draft_folder;
926 /* Note: This can fail (with a warning) if the message is not really already in a folder,
927 * because this function requires it to have a UID. */
928 helper = g_slice_new (SendNewMailHelper);
929 helper->mail_op = g_object_ref (self);
930 helper->notify = TRUE;
932 tmp_headers = tny_simple_list_new ();
933 tny_list_append (tmp_headers, (GObject*) header);
934 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
935 g_object_unref (tmp_headers);
936 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
938 g_object_unref (folder);
943 g_object_unref (header);
945 g_object_unref (info->draft_msg);
947 g_object_unref (draft_folder);
949 g_object_unref (outbox_folder);
950 if (info->transport_account)
951 g_object_unref (info->transport_account);
952 g_slice_free (SendNewMailInfo, info);
956 modest_mail_operation_send_new_mail (ModestMailOperation *self,
957 TnyTransportAccount *transport_account,
959 const gchar *from, const gchar *to,
960 const gchar *cc, const gchar *bcc,
961 const gchar *subject, const gchar *plain_body,
962 const gchar *html_body,
963 const GList *attachments_list,
964 const GList *images_list,
965 TnyHeaderFlags priority_flags)
967 ModestMailOperationPrivate *priv = NULL;
968 SendNewMailInfo *info;
970 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
971 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
973 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
974 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
975 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
976 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
978 modest_mail_operation_notify_start (self);
980 /* Check parametters */
982 /* Set status failed and set an error */
983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
984 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
985 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
986 _("Error trying to send a mail. You need to set at least one recipient"));
987 modest_mail_operation_notify_end (self);
990 info = g_slice_new0 (SendNewMailInfo);
991 info->transport_account = transport_account;
992 if (transport_account)
993 g_object_ref (transport_account);
994 info->draft_msg = draft_msg;
996 g_object_ref (draft_msg);
999 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1000 attachments_list, images_list, priority_flags,
1001 modest_mail_operation_send_new_mail_cb, info);
1007 TnyTransportAccount *transport_account;
1009 SaveToDraftstCallback callback;
1013 ModestMailOperation *mailop;
1014 } SaveToDraftsAddMsgInfo;
1017 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1022 ModestMailOperationPrivate *priv = NULL;
1023 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1024 GError *io_error = NULL;
1026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1028 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1029 io_error = priv->error;
1033 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1034 g_error_free(priv->error);
1037 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1039 if ((!priv->error) && (info->draft_msg != NULL)) {
1040 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1041 TnyFolder *src_folder = tny_header_get_folder (header);
1043 /* Remove the old draft */
1044 tny_folder_remove_msg (src_folder, header, NULL);
1046 /* Synchronize to expunge and to update the msg counts */
1047 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1048 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1050 g_object_unref (G_OBJECT(header));
1051 g_object_unref (G_OBJECT(src_folder));
1055 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1057 g_error_free (io_error);
1060 } else if (io_error) {
1061 priv->error = io_error;
1062 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1064 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1067 /* Call the user callback */
1069 info->callback (info->mailop, info->msg, info->user_data);
1071 if (info->transport_account)
1072 g_object_unref (G_OBJECT(info->transport_account));
1073 if (info->draft_msg)
1074 g_object_unref (G_OBJECT (info->draft_msg));
1076 g_object_unref (G_OBJECT(info->drafts));
1078 g_object_unref (G_OBJECT (info->msg));
1080 modest_mail_operation_notify_end (info->mailop);
1081 g_object_unref(info->mailop);
1082 g_slice_free (SaveToDraftsAddMsgInfo, info);
1087 TnyTransportAccount *transport_account;
1089 SaveToDraftstCallback callback;
1094 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1098 TnyFolder *drafts = NULL;
1099 ModestMailOperationPrivate *priv = NULL;
1100 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1102 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1105 if (!(priv->error)) {
1106 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1107 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1108 "modest: failed to create a new msg\n");
1111 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1112 TNY_FOLDER_TYPE_DRAFTS);
1113 if (!drafts && !(priv->error)) {
1114 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1115 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1116 "modest: failed to create a new msg\n");
1120 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1121 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1122 cb_info->transport_account = g_object_ref(info->transport_account);
1123 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1124 cb_info->callback = info->callback;
1125 cb_info->user_data = info->user_data;
1126 cb_info->drafts = g_object_ref(drafts);
1127 cb_info->msg = g_object_ref(msg);
1128 cb_info->mailop = g_object_ref(self);
1129 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1132 /* Call the user callback */
1133 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1135 info->callback (self, msg, info->user_data);
1136 modest_mail_operation_notify_end (self);
1140 g_object_unref (G_OBJECT(drafts));
1141 if (info->draft_msg)
1142 g_object_unref (G_OBJECT (info->draft_msg));
1143 if (info->transport_account)
1144 g_object_unref (G_OBJECT(info->transport_account));
1145 g_slice_free (SaveToDraftsInfo, info);
1149 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1150 TnyTransportAccount *transport_account,
1152 const gchar *from, const gchar *to,
1153 const gchar *cc, const gchar *bcc,
1154 const gchar *subject, const gchar *plain_body,
1155 const gchar *html_body,
1156 const GList *attachments_list,
1157 const GList *images_list,
1158 TnyHeaderFlags priority_flags,
1159 SaveToDraftstCallback callback,
1162 ModestMailOperationPrivate *priv = NULL;
1163 SaveToDraftsInfo *info = NULL;
1165 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1166 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1168 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1170 /* Get account and set it into mail_operation */
1171 priv->account = g_object_ref (transport_account);
1172 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1174 info = g_slice_new0 (SaveToDraftsInfo);
1175 info->transport_account = g_object_ref (transport_account);
1176 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1177 info->callback = callback;
1178 info->user_data = user_data;
1180 modest_mail_operation_notify_start (self);
1181 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1182 attachments_list, images_list, priority_flags,
1183 modest_mail_operation_save_to_drafts_cb, info);
1188 ModestMailOperation *mail_op;
1189 TnyMimePart *mime_part;
1191 GetMimePartSizeCallback callback;
1193 } GetMimePartSizeInfo;
1195 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1196 /* We use this folder observer to track the headers that have been
1197 * added to a folder */
1200 TnyList *new_headers;
1201 } InternalFolderObserver;
1204 GObjectClass parent;
1205 } InternalFolderObserverClass;
1207 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1209 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1210 internal_folder_observer,
1212 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1216 foreach_add_item (gpointer header, gpointer user_data)
1218 tny_list_prepend (TNY_LIST (user_data),
1222 /* This is the method that looks for new messages in a folder */
1224 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1226 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1228 TnyFolderChangeChanged changed;
1230 changed = tny_folder_change_get_changed (change);
1232 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1235 /* Get added headers */
1236 list = tny_simple_list_new ();
1237 tny_folder_change_get_added_headers (change, list);
1239 /* Add them to the folder observer */
1240 tny_list_foreach (list, foreach_add_item,
1241 derived->new_headers);
1243 g_object_unref (G_OBJECT (list));
1248 internal_folder_observer_init (InternalFolderObserver *self)
1250 self->new_headers = tny_simple_list_new ();
1253 internal_folder_observer_finalize (GObject *object)
1255 InternalFolderObserver *self;
1257 self = (InternalFolderObserver *) object;
1258 g_object_unref (self->new_headers);
1260 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1263 tny_folder_observer_init (TnyFolderObserverIface *iface)
1265 iface->update = internal_folder_observer_update;
1268 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1270 GObjectClass *object_class;
1272 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1273 object_class = (GObjectClass*) klass;
1274 object_class->finalize = internal_folder_observer_finalize;
1278 destroy_update_account_info (UpdateAccountInfo *info)
1280 g_free (info->account_name);
1281 g_object_unref (info->folders);
1282 g_object_unref (info->mail_op);
1283 g_slice_free (UpdateAccountInfo, info);
1288 update_account_send_mail (UpdateAccountInfo *info)
1290 TnyTransportAccount *transport_account = NULL;
1291 ModestTnyAccountStore *account_store;
1293 account_store = modest_runtime_get_account_store ();
1295 /* We don't try to send messages while sending mails is blocked */
1296 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1299 /* Get the transport account */
1300 transport_account = (TnyTransportAccount *)
1301 modest_tny_account_store_get_transport_account_for_open_connection (account_store,
1302 info->account_name);
1304 if (transport_account) {
1305 ModestTnySendQueue *send_queue;
1309 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1310 g_object_unref (transport_account);
1312 if (TNY_IS_SEND_QUEUE (send_queue)) {
1313 /* Get outbox folder */
1314 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1315 if (outbox) { /* this could fail in some cases */
1316 num_messages = tny_folder_get_all_count (outbox);
1317 g_object_unref (outbox);
1319 g_warning ("%s: could not get outbox", __FUNCTION__);
1323 if (num_messages != 0) {
1324 /* Reenable suspended items */
1325 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1328 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1329 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1337 update_account_get_msg_async_cb (TnyFolder *folder,
1343 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1344 ModestMailOperationPrivate *priv;
1346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1349 if (TNY_IS_MSG (msg)) {
1350 TnyHeader *header = tny_msg_get_header (msg);
1353 ModestMailOperationState *state;
1354 state = modest_mail_operation_clone_state (msg_info->mail_op);
1355 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1356 state->bytes_done = msg_info->sum_total_bytes;
1357 state->bytes_total = msg_info->total_bytes;
1359 /* Notify the status change. Only notify about changes
1360 referred to bytes */
1361 g_signal_emit (G_OBJECT (msg_info->mail_op),
1362 signals[PROGRESS_CHANGED_SIGNAL],
1365 g_object_unref (header);
1366 g_slice_free (ModestMailOperationState, state);
1370 if (priv->done == priv->total) {
1371 TnyList *new_headers;
1372 UpdateAccountInfo *info;
1374 /* After getting all the messages send the ones in the
1376 info = (UpdateAccountInfo *) msg_info->user_data;
1377 update_account_send_mail (info);
1379 /* Check if the operation was a success */
1381 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1383 /* Call the user callback and free */
1384 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1385 update_account_notify_user_and_free (info, new_headers);
1386 g_object_unref (new_headers);
1388 /* Delete the helper */
1389 g_object_unref (msg_info->more_msgs);
1390 g_object_unref (msg_info->mail_op);
1391 g_slice_free (GetMsgInfo, msg_info);
1396 update_account_notify_user_and_free (UpdateAccountInfo *info,
1397 TnyList *new_headers)
1399 /* Set the account back to not busy */
1400 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1401 info->account_name, FALSE);
1405 info->callback (info->mail_op, new_headers, info->user_data);
1407 /* Mail operation end */
1408 modest_mail_operation_notify_end (info->mail_op);
1412 g_object_unref (new_headers);
1413 destroy_update_account_info (info);
1417 inbox_refreshed_cb (TnyFolder *inbox,
1422 UpdateAccountInfo *info;
1423 ModestMailOperationPrivate *priv;
1424 TnyIterator *new_headers_iter;
1425 GPtrArray *new_headers_array = NULL;
1426 gint max_size, retrieve_limit, i;
1427 ModestAccountMgr *mgr;
1428 ModestAccountRetrieveType retrieve_type;
1429 TnyList *new_headers = NULL;
1430 gboolean headers_only, ignore_limit;
1432 info = (UpdateAccountInfo *) user_data;
1433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1434 mgr = modest_runtime_get_account_mgr ();
1436 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1437 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1439 if (canceled || err) {
1440 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1442 priv->error = g_error_copy (err);
1444 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1445 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1448 tny_folder_remove_observer (inbox, info->inbox_observer);
1449 g_object_unref (info->inbox_observer);
1450 info->inbox_observer = NULL;
1452 /* Notify the user about the error and then exit */
1453 update_account_notify_user_and_free (info, NULL);
1458 /* Try to send anyway */
1462 /* Get the message max size */
1463 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1464 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1466 max_size = G_MAXINT;
1468 max_size = max_size * KB;
1470 /* Create the new headers array. We need it to sort the
1471 new headers by date */
1472 new_headers_array = g_ptr_array_new ();
1473 if (info->inbox_observer) {
1474 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1475 while (!tny_iterator_is_done (new_headers_iter)) {
1476 TnyHeader *header = NULL;
1478 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1479 /* Apply per-message size limits */
1480 if (tny_header_get_message_size (header) < max_size)
1481 g_ptr_array_add (new_headers_array, g_object_ref (header));
1483 g_object_unref (header);
1484 tny_iterator_next (new_headers_iter);
1486 g_object_unref (new_headers_iter);
1488 tny_folder_remove_observer (inbox, info->inbox_observer);
1489 g_object_unref (info->inbox_observer);
1490 info->inbox_observer = NULL;
1493 if (new_headers_array->len == 0) {
1494 g_ptr_array_free (new_headers_array, FALSE);
1498 /* Get per-account message amount retrieval limit */
1499 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1500 if (retrieve_limit == 0)
1501 retrieve_limit = G_MAXINT;
1503 /* Get per-account retrieval type */
1504 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1505 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1508 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1510 /* Ask the users if they want to retrieve all the messages
1511 even though the limit was exceeded */
1512 ignore_limit = FALSE;
1513 if (new_headers_array->len > retrieve_limit) {
1514 /* Ask the user if a callback has been specified and
1515 if the mail operation has a source (this means that
1516 was invoked by the user and not automatically by a
1518 if (info->retrieve_all_cb && priv->source)
1519 ignore_limit = info->retrieve_all_cb (priv->source,
1520 new_headers_array->len,
1524 /* Copy the headers to a list and free the array */
1525 new_headers = tny_simple_list_new ();
1526 for (i=0; i < new_headers_array->len; i++) {
1527 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1528 tny_list_append (new_headers, G_OBJECT (header));
1530 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1531 g_ptr_array_free (new_headers_array, FALSE);
1533 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1536 GetMsgInfo *msg_info;
1540 priv->total = tny_list_get_length (new_headers);
1542 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1544 iter = tny_list_create_iterator (new_headers);
1546 /* Create the message info */
1547 msg_info = g_slice_new0 (GetMsgInfo);
1548 msg_info->mail_op = g_object_ref (info->mail_op);
1549 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1550 msg_info->more_msgs = g_object_ref (iter);
1551 msg_info->user_data = info;
1553 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1554 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1555 TnyFolder *folder = tny_header_get_folder (header);
1557 /* Get message in an async way */
1558 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1561 g_object_unref (folder);
1564 tny_iterator_next (iter);
1566 g_object_unref (iter);
1568 /* The mail operation will finish when the last
1569 message is retrieved */
1573 /* If we don't have to retrieve the new messages then
1575 update_account_send_mail (info);
1577 /* Check if the operation was a success */
1579 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1581 /* Call the user callback and free */
1582 update_account_notify_user_and_free (info, new_headers);
1586 inbox_refresh_status_update (GObject *obj,
1590 UpdateAccountInfo *info = NULL;
1591 ModestMailOperation *self = NULL;
1592 ModestMailOperationPrivate *priv = NULL;
1593 ModestMailOperationState *state;
1595 g_return_if_fail (user_data != NULL);
1596 g_return_if_fail (status != NULL);
1598 /* Show only the status information we want */
1599 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1602 info = (UpdateAccountInfo *) user_data;
1603 self = info->mail_op;
1604 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1606 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1608 priv->done = status->position;
1609 priv->total = status->of_total;
1611 state = modest_mail_operation_clone_state (self);
1613 /* This is not a GDK lock because we are a Tinymail callback and
1614 * Tinymail already acquires the Gdk lock */
1615 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1617 g_slice_free (ModestMailOperationState, state);
1621 recurse_folders_async_cb (TnyFolderStore *folder_store,
1627 UpdateAccountInfo *info;
1628 ModestMailOperationPrivate *priv;
1630 info = (UpdateAccountInfo *) user_data;
1631 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1633 if (err || canceled) {
1634 /* If the error was previosly set by another callback
1635 don't set it again */
1637 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1639 priv->error = g_error_copy (err);
1641 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1642 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1646 /* We're not getting INBOX children if we don't want to poke all */
1647 TnyIterator *iter = tny_list_create_iterator (list);
1648 while (!tny_iterator_is_done (iter)) {
1649 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1651 /* Add to the list of all folders */
1652 tny_list_append (info->folders, (GObject *) folder);
1654 if (info->poke_all) {
1655 TnyList *folders = tny_simple_list_new ();
1656 /* Add pending call */
1657 info->pending_calls++;
1659 tny_folder_store_get_folders_async (folder, folders, NULL,
1660 recurse_folders_async_cb,
1662 g_object_unref (folders);
1665 g_object_unref (G_OBJECT (folder));
1667 tny_iterator_next (iter);
1669 g_object_unref (G_OBJECT (iter));
1672 /* Remove my own pending call */
1673 info->pending_calls--;
1675 /* This means that we have all the folders */
1676 if (info->pending_calls == 0) {
1677 TnyIterator *iter_all_folders;
1678 TnyFolder *inbox = NULL;
1680 /* If there was any error do not continue */
1682 update_account_notify_user_and_free (info, NULL);
1686 iter_all_folders = tny_list_create_iterator (info->folders);
1688 /* Do a poke status over all folders */
1689 while (!tny_iterator_is_done (iter_all_folders) &&
1690 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1691 TnyFolder *folder = NULL;
1693 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1695 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1696 /* Get a reference to the INBOX */
1697 inbox = g_object_ref (folder);
1699 /* Issue a poke status over the folder */
1701 tny_folder_poke_status (folder);
1704 /* Free and go to next */
1705 g_object_unref (folder);
1706 tny_iterator_next (iter_all_folders);
1708 g_object_unref (iter_all_folders);
1710 /* Refresh the INBOX */
1712 /* Refresh the folder. Our observer receives
1713 * the new emails during folder refreshes, so
1714 * we can use observer->new_headers
1716 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1717 tny_folder_add_observer (inbox, info->inbox_observer);
1719 /* Refresh the INBOX */
1720 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1721 g_object_unref (inbox);
1723 /* We could not perform the inbox refresh but
1724 we'll try to send mails anyway */
1725 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1731 modest_mail_operation_update_account (ModestMailOperation *self,
1732 const gchar *account_name,
1734 gboolean interactive,
1735 RetrieveAllCallback retrieve_all_cb,
1736 UpdateAccountCallback callback,
1739 UpdateAccountInfo *info = NULL;
1740 ModestMailOperationPrivate *priv = NULL;
1741 ModestTnyAccountStore *account_store = NULL;
1743 ModestMailOperationState *state;
1745 /* Init mail operation */
1746 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1750 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1752 /* Get the store account */
1753 account_store = modest_runtime_get_account_store ();
1755 modest_tny_account_store_get_server_account (account_store,
1757 TNY_ACCOUNT_TYPE_STORE);
1759 /* The above function could return NULL */
1760 if (!priv->account) {
1761 /* Check if the operation was a success */
1762 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1763 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1767 /* Call the user callback */
1769 callback (self, NULL, user_data);
1771 /* Notify about operation end */
1772 modest_mail_operation_notify_end (self);
1777 /* We have once seen priv->account getting finalized during this code,
1778 * therefore adding a reference (bug #82296) */
1780 g_object_ref (priv->account);
1782 /* Create the helper object */
1783 info = g_slice_new0 (UpdateAccountInfo);
1784 info->pending_calls = 1;
1785 info->folders = tny_simple_list_new ();
1786 info->mail_op = g_object_ref (self);
1787 info->poke_all = poke_all;
1788 info->interactive = interactive;
1789 info->account_name = g_strdup (account_name);
1790 info->callback = callback;
1791 info->user_data = user_data;
1792 info->retrieve_all_cb = retrieve_all_cb;
1794 /* Set account busy */
1795 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1796 modest_mail_operation_notify_start (self);
1798 /* notify about the start of the operation */
1799 state = modest_mail_operation_clone_state (self);
1803 /* Start notifying progress */
1804 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1805 g_slice_free (ModestMailOperationState, state);
1807 /* Get all folders and continue in the callback */
1808 folders = tny_simple_list_new ();
1809 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1811 recurse_folders_async_cb,
1813 g_object_unref (folders);
1815 g_object_unref (priv->account);
1820 * Used to notify the queue from the main
1821 * loop. We call it inside an idle call to achieve that
1824 idle_notify_queue (gpointer data)
1826 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1828 gdk_threads_enter ();
1829 modest_mail_operation_notify_end (mail_op);
1830 gdk_threads_leave ();
1831 g_object_unref (mail_op);
1837 compare_headers_by_date (gconstpointer a,
1840 TnyHeader **header1, **header2;
1841 time_t sent1, sent2;
1843 header1 = (TnyHeader **) a;
1844 header2 = (TnyHeader **) b;
1846 sent1 = tny_header_get_date_sent (*header1);
1847 sent2 = tny_header_get_date_sent (*header2);
1849 /* We want the most recent ones (greater time_t) at the
1858 /* ******************************************************************* */
1859 /* ************************** STORE ACTIONS ************************* */
1860 /* ******************************************************************* */
1863 ModestMailOperation *mail_op;
1864 CreateFolderUserCallback callback;
1870 create_folder_cb (TnyFolderStore *parent_folder,
1872 TnyFolder *new_folder,
1876 ModestMailOperationPrivate *priv;
1877 CreateFolderInfo *info;
1879 info = (CreateFolderInfo *) user_data;
1880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1882 if (canceled || err) {
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1885 priv->error = g_error_copy (err);
1887 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1888 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1891 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1894 /* The user will unref the new_folder */
1896 info->callback (info->mail_op, parent_folder,
1897 new_folder, info->user_data);
1899 /* Notify about operation end */
1900 modest_mail_operation_notify_end (info->mail_op);
1903 g_object_unref (info->mail_op);
1904 g_slice_free (CreateFolderInfo, info);
1908 modest_mail_operation_create_folder (ModestMailOperation *self,
1909 TnyFolderStore *parent,
1911 CreateFolderUserCallback callback,
1914 ModestMailOperationPrivate *priv;
1916 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1917 g_return_if_fail (name);
1919 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1920 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1921 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1922 g_object_ref (parent) :
1923 modest_tny_folder_get_account (TNY_FOLDER (parent));
1925 /* Check for already existing folder */
1926 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1928 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1929 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1930 _CS("ckdg_ib_folder_already_exists"));
1934 if (TNY_IS_FOLDER (parent)) {
1935 /* Check folder rules */
1936 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1937 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1938 /* Set status failed and set an error */
1939 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1940 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1941 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1942 _("mail_in_ui_folder_create_error"));
1946 if (!strcmp (name, " ") || strchr (name, '/')) {
1947 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1948 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1949 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1950 _("mail_in_ui_folder_create_error"));
1954 CreateFolderInfo *info;
1956 info = g_slice_new0 (CreateFolderInfo);
1957 info->mail_op = g_object_ref (self);
1958 info->callback = callback;
1959 info->user_data = user_data;
1961 modest_mail_operation_notify_start (self);
1963 /* Create the folder */
1964 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1967 /* Call the user callback anyway */
1969 callback (self, parent, NULL, user_data);
1970 /* Notify about operation end */
1971 modest_mail_operation_notify_end (self);
1976 modest_mail_operation_remove_folder (ModestMailOperation *self,
1978 gboolean remove_to_trash)
1980 ModestMailOperationPrivate *priv;
1981 ModestTnyFolderRules rules;
1983 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1984 g_return_if_fail (TNY_IS_FOLDER (folder));
1986 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1988 /* Check folder rules */
1989 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1990 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1991 /* Set status failed and set an error */
1992 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1993 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1994 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1995 _("mail_in_ui_folder_delete_error"));
1999 /* Get the account */
2000 priv->account = modest_tny_folder_get_account (folder);
2001 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2003 /* Delete folder or move to trash */
2004 if (remove_to_trash) {
2005 TnyFolder *trash_folder = NULL;
2006 trash_folder = modest_tny_account_get_special_folder (priv->account,
2007 TNY_FOLDER_TYPE_TRASH);
2008 /* TODO: error_handling */
2010 modest_mail_operation_notify_start (self);
2011 modest_mail_operation_xfer_folder (self, folder,
2012 TNY_FOLDER_STORE (trash_folder),
2014 g_object_unref (trash_folder);
2016 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2019 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2021 modest_mail_operation_notify_start (self);
2022 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2023 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2026 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2028 g_object_unref (parent);
2030 g_warning ("%s: could not get parent folder", __FUNCTION__);
2034 /* Notify about operation end */
2035 modest_mail_operation_notify_end (self);
2039 transfer_folder_status_cb (GObject *obj,
2043 ModestMailOperation *self;
2044 ModestMailOperationPrivate *priv;
2045 ModestMailOperationState *state;
2046 XFerFolderAsyncHelper *helper;
2048 g_return_if_fail (status != NULL);
2050 /* Show only the status information we want */
2051 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2054 helper = (XFerFolderAsyncHelper *) user_data;
2055 g_return_if_fail (helper != NULL);
2057 self = helper->mail_op;
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2060 priv->done = status->position;
2061 priv->total = status->of_total;
2063 state = modest_mail_operation_clone_state (self);
2065 /* This is not a GDK lock because we are a Tinymail callback
2066 * which is already GDK locked by Tinymail */
2068 /* no gdk_threads_enter (), CHECKED */
2070 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2072 /* no gdk_threads_leave (), CHECKED */
2074 g_slice_free (ModestMailOperationState, state);
2079 transfer_folder_cb (TnyFolder *folder,
2081 TnyFolderStore *into,
2082 TnyFolder *new_folder,
2086 XFerFolderAsyncHelper *helper;
2087 ModestMailOperation *self = NULL;
2088 ModestMailOperationPrivate *priv = NULL;
2090 helper = (XFerFolderAsyncHelper *) user_data;
2091 g_return_if_fail (helper != NULL);
2093 self = helper->mail_op;
2094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2097 priv->error = g_error_copy (err);
2099 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2100 } else if (cancelled) {
2101 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2102 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2103 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2104 _("Transference of %s was cancelled."),
2105 tny_folder_get_name (folder));
2108 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2111 /* Notify about operation end */
2112 modest_mail_operation_notify_end (self);
2114 /* If user defined callback function was defined, call it */
2115 if (helper->user_callback) {
2117 /* This is not a GDK lock because we are a Tinymail callback
2118 * which is already GDK locked by Tinymail */
2120 /* no gdk_threads_enter (), CHECKED */
2121 helper->user_callback (self, new_folder, helper->user_data);
2122 /* no gdk_threads_leave () , CHECKED */
2126 g_object_unref (helper->mail_op);
2127 g_slice_free (XFerFolderAsyncHelper, helper);
2132 * This function checks if the new name is a valid name for our local
2133 * folders account. The new name could not be the same than then name
2134 * of any of the mandatory local folders
2136 * We can not rely on tinymail because tinymail does not check the
2137 * name of the virtual folders that the account could have in the case
2138 * that we're doing a rename (because it directly calls Camel which
2139 * knows nothing about our virtual folders).
2141 * In the case of an actual copy/move (i.e. move/copy a folder between
2142 * accounts) tinymail uses the tny_folder_store_create_account which
2143 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2144 * checks the new name of the folder, so this call in that case
2145 * wouldn't be needed. *But* NOTE that if tinymail changes its
2146 * implementation (if folder transfers within the same account is no
2147 * longer implemented as a rename) this call will allow Modest to work
2150 * If the new name is not valid, this function will set the status to
2151 * failed and will set also an error in the mail operation
2154 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2155 TnyFolderStore *into,
2156 const gchar *new_name)
2158 if (TNY_IS_ACCOUNT (into) &&
2159 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2160 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2162 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2163 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2164 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2165 _CS("ckdg_ib_folder_already_exists"));
2172 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2174 TnyFolderStore *parent,
2175 gboolean delete_original,
2176 XferFolderAsyncUserCallback user_callback,
2179 ModestMailOperationPrivate *priv = NULL;
2180 ModestTnyFolderRules parent_rules = 0, rules;
2181 XFerFolderAsyncHelper *helper = NULL;
2182 const gchar *folder_name = NULL;
2183 const gchar *error_msg;
2185 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2186 g_return_if_fail (TNY_IS_FOLDER (folder));
2187 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2189 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2190 folder_name = tny_folder_get_name (folder);
2192 /* Set the error msg */
2193 error_msg = _("mail_in_ui_folder_move_target_error");
2195 /* Get account and set it into mail_operation */
2196 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2197 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2198 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2200 /* Get folder rules */
2201 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2202 if (TNY_IS_FOLDER (parent))
2203 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2205 /* Apply operation constraints */
2206 if ((gpointer) parent == (gpointer) folder ||
2207 (!TNY_IS_FOLDER_STORE (parent)) ||
2208 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2211 } else if (TNY_IS_FOLDER (parent) &&
2212 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2216 } else if (TNY_IS_FOLDER (parent) &&
2217 TNY_IS_FOLDER_STORE (folder) &&
2218 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2219 TNY_FOLDER_STORE (folder))) {
2220 /* Do not move a parent into a child */
2222 } else if (TNY_IS_FOLDER_STORE (parent) &&
2223 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2224 /* Check that the new folder name is not used by any
2227 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2228 /* Check that the new folder name is not used by any
2229 special local folder */
2232 /* Create the helper */
2233 helper = g_slice_new0 (XFerFolderAsyncHelper);
2234 helper->mail_op = g_object_ref (self);
2235 helper->user_callback = user_callback;
2236 helper->user_data = user_data;
2238 /* Move/Copy folder */
2239 modest_mail_operation_notify_start (self);
2240 tny_folder_copy_async (folder,
2242 tny_folder_get_name (folder),
2245 transfer_folder_status_cb,
2251 /* Set status failed and set an error */
2252 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2253 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2254 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2257 /* Call the user callback if exists */
2259 user_callback (self, NULL, user_data);
2261 /* Notify the queue */
2262 modest_mail_operation_notify_end (self);
2266 modest_mail_operation_rename_folder (ModestMailOperation *self,
2269 XferFolderAsyncUserCallback user_callback,
2272 ModestMailOperationPrivate *priv;
2273 ModestTnyFolderRules rules;
2274 XFerFolderAsyncHelper *helper;
2276 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2277 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2278 g_return_if_fail (name);
2280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2282 /* Get account and set it into mail_operation */
2283 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2284 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2286 /* Check folder rules */
2287 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2288 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2290 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2293 TnyFolderStore *into;
2295 into = tny_folder_get_folder_store (folder);
2297 /* Check that the new folder name is not used by any
2298 special local folder */
2299 if (new_name_valid_if_local_account (priv, into, name)) {
2300 /* Create the helper */
2301 helper = g_slice_new0 (XFerFolderAsyncHelper);
2302 helper->mail_op = g_object_ref(self);
2303 helper->user_callback = user_callback;
2304 helper->user_data = user_data;
2306 /* Rename. Camel handles folder subscription/unsubscription */
2307 modest_mail_operation_notify_start (self);
2308 tny_folder_copy_async (folder, into, name, TRUE,
2310 transfer_folder_status_cb,
2312 g_object_unref (into);
2314 g_object_unref (into);
2321 /* Set status failed and set an error */
2322 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2323 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2324 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2325 _("FIXME: unable to rename"));
2328 user_callback (self, NULL, user_data);
2330 /* Notify about operation end */
2331 modest_mail_operation_notify_end (self);
2334 /* ******************************************************************* */
2335 /* ************************** MSG ACTIONS ************************* */
2336 /* ******************************************************************* */
2339 modest_mail_operation_get_msg (ModestMailOperation *self,
2341 gboolean progress_feedback,
2342 GetMsgAsyncUserCallback user_callback,
2345 GetMsgInfo *helper = NULL;
2347 ModestMailOperationPrivate *priv;
2349 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2350 g_return_if_fail (TNY_IS_HEADER (header));
2352 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2353 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2357 /* Check memory low */
2358 if (_check_memory_low (self)) {
2360 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2361 modest_mail_operation_notify_end (self);
2365 /* Get account and set it into mail_operation */
2366 folder = tny_header_get_folder (header);
2367 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2369 /* Check for cached messages */
2370 if (progress_feedback) {
2371 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2372 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2374 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2376 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2379 /* Create the helper */
2380 helper = g_slice_new0 (GetMsgInfo);
2381 helper->header = g_object_ref (header);
2382 helper->mail_op = g_object_ref (self);
2383 helper->user_callback = user_callback;
2384 helper->user_data = user_data;
2385 helper->destroy_notify = NULL;
2386 helper->last_total_bytes = 0;
2387 helper->sum_total_bytes = 0;
2388 helper->total_bytes = tny_header_get_message_size (header);
2389 helper->more_msgs = NULL;
2391 modest_mail_operation_notify_start (self);
2393 /* notify about the start of the operation */
2394 ModestMailOperationState *state;
2395 state = modest_mail_operation_clone_state (self);
2398 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2400 g_slice_free (ModestMailOperationState, state);
2402 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2404 g_object_unref (G_OBJECT (folder));
2408 get_msg_status_cb (GObject *obj,
2412 GetMsgInfo *helper = NULL;
2414 g_return_if_fail (status != NULL);
2416 /* Show only the status information we want */
2417 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2420 helper = (GetMsgInfo *) user_data;
2421 g_return_if_fail (helper != NULL);
2423 /* Notify progress */
2424 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2425 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2429 get_msg_async_cb (TnyFolder *folder,
2435 GetMsgInfo *info = NULL;
2436 ModestMailOperationPrivate *priv = NULL;
2439 info = (GetMsgInfo *) user_data;
2441 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2444 if (info->more_msgs) {
2445 tny_iterator_next (info->more_msgs);
2446 finished = (tny_iterator_is_done (info->more_msgs));
2448 finished = (priv->done == priv->total) ? TRUE : FALSE;
2451 /* If canceled by the user, ignore the error given by Tinymail */
2455 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2457 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2459 priv->error = g_error_copy ((const GError *) err);
2460 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2463 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2464 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2467 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2468 /* Set the success status before calling the user callback */
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2473 /* Call the user callback */
2474 if (info->user_callback)
2475 info->user_callback (info->mail_op, info->header, canceled,
2476 msg, err, info->user_data);
2478 /* Notify about operation end if this is the last callback */
2480 /* Free user data */
2481 if (info->destroy_notify)
2482 info->destroy_notify (info->user_data);
2484 /* Notify about operation end */
2485 modest_mail_operation_notify_end (info->mail_op);
2488 if (info->more_msgs)
2489 g_object_unref (info->more_msgs);
2490 g_object_unref (info->header);
2491 g_object_unref (info->mail_op);
2492 g_slice_free (GetMsgInfo, info);
2493 } else if (info->more_msgs) {
2494 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2495 TnyFolder *folder = tny_header_get_folder (header);
2497 g_object_unref (info->header);
2498 info->header = g_object_ref (header);
2500 /* Retrieve the next message */
2501 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2503 g_object_unref (header);
2504 g_object_unref (folder);
2506 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2511 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2512 TnyList *header_list,
2513 GetMsgAsyncUserCallback user_callback,
2515 GDestroyNotify notify)
2517 ModestMailOperationPrivate *priv = NULL;
2519 TnyIterator *iter = NULL;
2520 gboolean has_uncached_messages;
2522 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2524 /* Init mail operation */
2525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2526 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2528 priv->total = tny_list_get_length(header_list);
2530 /* Check memory low */
2531 if (_check_memory_low (self)) {
2532 if (user_callback) {
2533 TnyHeader *header = NULL;
2536 if (tny_list_get_length (header_list) > 0) {
2537 iter = tny_list_create_iterator (header_list);
2538 header = (TnyHeader *) tny_iterator_get_current (iter);
2539 g_object_unref (iter);
2541 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2543 g_object_unref (header);
2547 /* Notify about operation end */
2548 modest_mail_operation_notify_end (self);
2552 /* Check uncached messages */
2553 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2554 !has_uncached_messages && !tny_iterator_is_done (iter);
2555 tny_iterator_next (iter)) {
2558 header = (TnyHeader *) tny_iterator_get_current (iter);
2559 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2560 has_uncached_messages = TRUE;
2561 g_object_unref (header);
2563 g_object_unref (iter);
2564 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2566 /* Get account and set it into mail_operation */
2567 if (tny_list_get_length (header_list) >= 1) {
2568 TnyIterator *iterator = tny_list_create_iterator (header_list);
2569 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2571 TnyFolder *folder = tny_header_get_folder (header);
2573 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2574 g_object_unref (folder);
2576 g_object_unref (header);
2578 g_object_unref (iterator);
2581 msg_list_size = compute_message_list_size (header_list, 0);
2583 modest_mail_operation_notify_start (self);
2584 iter = tny_list_create_iterator (header_list);
2585 if (!tny_iterator_is_done (iter)) {
2586 /* notify about the start of the operation */
2587 ModestMailOperationState *state;
2588 state = modest_mail_operation_clone_state (self);
2591 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2594 GetMsgInfo *msg_info = NULL;
2595 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2596 TnyFolder *folder = tny_header_get_folder (header);
2598 /* Create the message info */
2599 msg_info = g_slice_new0 (GetMsgInfo);
2600 msg_info->mail_op = g_object_ref (self);
2601 msg_info->header = g_object_ref (header);
2602 msg_info->more_msgs = g_object_ref (iter);
2603 msg_info->user_callback = user_callback;
2604 msg_info->user_data = user_data;
2605 msg_info->destroy_notify = notify;
2606 msg_info->last_total_bytes = 0;
2607 msg_info->sum_total_bytes = 0;
2608 msg_info->total_bytes = msg_list_size;
2610 /* The callback will call it per each header */
2611 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2613 /* Free and go on */
2614 g_object_unref (header);
2615 g_object_unref (folder);
2616 g_slice_free (ModestMailOperationState, state);
2618 g_object_unref (iter);
2623 remove_msgs_async_cb (TnyFolder *folder,
2628 gboolean expunge, leave_on_server;
2629 const gchar *account_name;
2631 TnyAccount *account;
2632 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2633 ModestMailOperation *self;
2634 ModestMailOperationPrivate *priv;
2636 self = (ModestMailOperation *) user_data;
2637 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2639 if (canceled || err) {
2640 /* If canceled by the user, ignore the error given by Tinymail */
2642 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2644 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2645 priv->error = g_error_copy ((const GError *) err);
2646 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2649 modest_mail_operation_notify_end (self);
2650 g_object_unref (self);
2654 account = tny_folder_get_account (folder);
2655 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2657 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2659 proto = tny_account_get_proto (account);
2660 g_object_unref (account);
2663 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2665 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2666 modest_tny_folder_is_remote_folder (folder) == FALSE)
2672 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2677 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2679 gboolean remove_to_trash /*ignored*/)
2681 TnyFolder *folder = NULL;
2682 ModestMailOperationPrivate *priv;
2683 TnyIterator *iter = NULL;
2684 TnyHeader *header = NULL;
2685 TnyList *remove_headers = NULL;
2686 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2688 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2689 g_return_if_fail (TNY_IS_LIST (headers));
2691 if (remove_to_trash)
2692 g_warning ("remove to trash is not implemented");
2694 if (tny_list_get_length(headers) == 0) {
2695 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2696 goto cleanup; /* nothing to do */
2699 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2700 remove_headers = g_object_ref(headers);
2702 /* Get folder from first header and sync it */
2703 iter = tny_list_create_iterator (headers);
2704 header = TNY_HEADER (tny_iterator_get_current (iter));
2706 folder = tny_header_get_folder (header);
2707 if (!TNY_IS_FOLDER(folder)) {
2708 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2712 /* Don't remove messages that are being sent */
2713 if (modest_tny_folder_is_local_folder (folder)) {
2714 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2716 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2717 TnyTransportAccount *traccount = NULL;
2718 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2719 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2721 ModestTnySendQueueStatus status;
2722 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2724 if (TNY_IS_SEND_QUEUE (send_queue)) {
2725 TnyIterator *iter = tny_list_create_iterator(headers);
2726 g_object_unref(remove_headers);
2727 remove_headers = TNY_LIST(tny_simple_list_new());
2728 while (!tny_iterator_is_done(iter)) {
2730 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2731 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2732 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2733 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2734 tny_list_append(remove_headers, G_OBJECT(hdr));
2736 g_object_unref(hdr);
2738 tny_iterator_next(iter);
2740 g_object_unref(iter);
2742 g_object_unref(traccount);
2746 /* Get account and set it into mail_operation */
2747 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2748 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2749 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2751 /* remove message from folder */
2752 modest_mail_operation_notify_start (self);
2753 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2754 NULL, g_object_ref (self));
2758 g_object_unref (remove_headers);
2760 g_object_unref (header);
2762 g_object_unref (iter);
2764 g_object_unref (folder);
2768 notify_progress_of_multiple_messages (ModestMailOperation *self,
2770 gint *last_total_bytes,
2771 gint *sum_total_bytes,
2773 gboolean increment_done)
2775 ModestMailOperationPrivate *priv;
2776 ModestMailOperationState *state;
2777 gboolean is_num_bytes = FALSE;
2779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2781 /* We know that tinymail sends us information about
2782 * transferred bytes with this particular message
2784 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2785 * I just added the 'if' so we don't get runtime warning)
2787 if (status->message)
2788 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2790 state = modest_mail_operation_clone_state (self);
2791 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2792 /* We know that we're in a different message when the
2793 total number of bytes to transfer is different. Of
2794 course it could fail if we're transferring messages
2795 of the same size, but this is a workarround */
2796 if (status->of_total != *last_total_bytes) {
2797 /* We need to increment the done when there is
2798 no information about each individual
2799 message, we need to do this in message
2800 transfers, and we don't do it for getting
2804 *sum_total_bytes += *last_total_bytes;
2805 *last_total_bytes = status->of_total;
2807 state->bytes_done += status->position + *sum_total_bytes;
2808 state->bytes_total = total_bytes;
2810 /* Notify the status change. Only notify about changes
2811 referred to bytes */
2812 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2816 g_slice_free (ModestMailOperationState, state);
2820 transfer_msgs_status_cb (GObject *obj,
2824 XFerMsgsAsyncHelper *helper;
2826 g_return_if_fail (status != NULL);
2828 /* Show only the status information we want */
2829 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2832 helper = (XFerMsgsAsyncHelper *) user_data;
2833 g_return_if_fail (helper != NULL);
2835 /* Notify progress */
2836 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2837 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2841 transfer_msgs_sync_folder_cb (TnyFolder *self,
2846 XFerMsgsAsyncHelper *helper;
2847 /* We don't care here about the results of the
2849 helper = (XFerMsgsAsyncHelper *) user_data;
2851 /* Notify about operation end */
2852 modest_mail_operation_notify_end (helper->mail_op);
2854 /* If user defined callback function was defined, call it */
2855 if (helper->user_callback)
2856 helper->user_callback (helper->mail_op, helper->user_data);
2859 if (helper->more_msgs)
2860 g_object_unref (helper->more_msgs);
2861 if (helper->headers)
2862 g_object_unref (helper->headers);
2863 if (helper->dest_folder)
2864 g_object_unref (helper->dest_folder);
2865 if (helper->mail_op)
2866 g_object_unref (helper->mail_op);
2867 g_slice_free (XFerMsgsAsyncHelper, helper);
2871 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2873 XFerMsgsAsyncHelper *helper;
2874 ModestMailOperation *self;
2875 ModestMailOperationPrivate *priv;
2876 gboolean finished = TRUE;
2878 helper = (XFerMsgsAsyncHelper *) user_data;
2879 self = helper->mail_op;
2881 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2884 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2886 priv->error = g_error_copy (err);
2888 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2889 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2890 if (helper->more_msgs) {
2891 /* We'll transfer the next message in the list */
2892 tny_iterator_next (helper->more_msgs);
2893 if (!tny_iterator_is_done (helper->more_msgs)) {
2894 GObject *next_header;
2895 g_object_unref (helper->headers);
2896 helper->headers = tny_simple_list_new ();
2897 next_header = tny_iterator_get_current (helper->more_msgs);
2898 tny_list_append (helper->headers, next_header);
2899 g_object_unref (next_header);
2905 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2910 /* Synchronize the source folder contents. This should
2911 be done by tinymail but the camel_folder_sync it's
2912 actually disabled in transfer_msgs_thread_clean
2913 because it's supposed to cause hangs */
2914 tny_folder_sync_async (folder, helper->delete,
2915 transfer_msgs_sync_folder_cb,
2918 /* Transfer more messages */
2919 tny_folder_transfer_msgs_async (folder,
2921 helper->dest_folder,
2924 transfer_msgs_status_cb,
2929 /* Computes the size of the messages the headers in the list belongs
2930 to. If num_elements is different from 0 then it only takes into
2931 account the first num_elements for the calculation */
2933 compute_message_list_size (TnyList *headers,
2937 guint size = 0, element = 0;
2939 /* If num_elements is not valid then take all into account */
2940 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2941 num_elements = tny_list_get_length (headers);
2943 iter = tny_list_create_iterator (headers);
2944 while (!tny_iterator_is_done (iter) && element < num_elements) {
2945 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2946 size += tny_header_get_message_size (header);
2947 g_object_unref (header);
2948 tny_iterator_next (iter);
2951 g_object_unref (iter);
2957 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2960 gboolean delete_original,
2961 XferMsgsAsyncUserCallback user_callback,
2964 ModestMailOperationPrivate *priv = NULL;
2965 TnyIterator *iter = NULL;
2966 TnyFolder *src_folder = NULL;
2967 XFerMsgsAsyncHelper *helper = NULL;
2968 TnyHeader *header = NULL;
2969 ModestTnyFolderRules rules = 0;
2970 TnyAccount *dst_account = NULL;
2971 gboolean leave_on_server;
2972 ModestMailOperationState *state;
2974 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2975 g_return_if_fail (headers && TNY_IS_LIST (headers));
2976 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2978 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2979 priv->total = tny_list_get_length (headers);
2981 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2982 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2984 /* Apply folder rules */
2985 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2986 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2987 /* Set status failed and set an error */
2988 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2990 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2991 _CS("ckct_ib_unable_to_paste_here"));
2992 /* Notify the queue */
2993 modest_mail_operation_notify_end (self);
2997 /* Get source folder */
2998 iter = tny_list_create_iterator (headers);
2999 header = TNY_HEADER (tny_iterator_get_current (iter));
3001 src_folder = tny_header_get_folder (header);
3002 g_object_unref (header);
3004 g_object_unref (iter);
3006 if (src_folder == NULL) {
3007 /* Notify the queue */
3008 modest_mail_operation_notify_end (self);
3010 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3015 /* Check folder source and destination */
3016 if (src_folder == folder) {
3017 /* Set status failed and set an error */
3018 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3019 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3020 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3021 _("mail_in_ui_folder_copy_target_error"));
3023 /* Notify the queue */
3024 modest_mail_operation_notify_end (self);
3027 g_object_unref (src_folder);
3031 /* Create the helper */
3032 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3033 helper->mail_op = g_object_ref(self);
3034 helper->dest_folder = g_object_ref(folder);
3035 helper->user_callback = user_callback;
3036 helper->user_data = user_data;
3037 helper->last_total_bytes = 0;
3038 helper->sum_total_bytes = 0;
3039 helper->total_bytes = compute_message_list_size (headers, 0);
3041 /* Get account and set it into mail_operation */
3042 priv->account = modest_tny_folder_get_account (src_folder);
3043 dst_account = modest_tny_folder_get_account (folder);
3045 if (priv->account == dst_account) {
3046 /* Transfer all messages at once using the fast
3047 * method. Note that depending on the server this
3048 * might not be that fast, and might not be
3049 * user-cancellable either */
3050 helper->headers = g_object_ref (headers);
3051 helper->more_msgs = NULL;
3053 /* Transfer messages one by one so the user can cancel
3056 helper->headers = tny_simple_list_new ();
3057 helper->more_msgs = tny_list_create_iterator (headers);
3058 hdr = tny_iterator_get_current (helper->more_msgs);
3059 tny_list_append (helper->headers, hdr);
3060 g_object_unref (hdr);
3063 /* If leave_on_server is set to TRUE then don't use
3064 delete_original, we always pass FALSE. This is because
3065 otherwise tinymail will try to sync the source folder and
3066 this could cause an error if we're offline while
3067 transferring an already downloaded message from a POP
3069 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3070 MODEST_PROTOCOL_STORE_POP) {
3071 const gchar *account_name;
3073 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3074 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3077 leave_on_server = FALSE;
3080 /* Do not delete messages if leave on server is TRUE */
3081 helper->delete = (leave_on_server) ? FALSE : delete_original;
3083 modest_mail_operation_notify_start (self);
3085 /* Start notifying progress */
3086 state = modest_mail_operation_clone_state (self);
3089 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3090 g_slice_free (ModestMailOperationState, state);
3092 tny_folder_transfer_msgs_async (src_folder,
3097 transfer_msgs_status_cb,
3099 g_object_unref (src_folder);
3100 g_object_unref (dst_account);
3105 on_refresh_folder (TnyFolder *folder,
3110 RefreshAsyncHelper *helper = NULL;
3111 ModestMailOperation *self = NULL;
3112 ModestMailOperationPrivate *priv = NULL;
3114 helper = (RefreshAsyncHelper *) user_data;
3115 self = helper->mail_op;
3116 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3118 g_return_if_fail(priv!=NULL);
3121 priv->error = g_error_copy (error);
3122 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3127 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3128 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3129 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3130 _("Error trying to refresh the contents of %s"),
3131 tny_folder_get_name (folder));
3135 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3138 /* Call user defined callback, if it exists */
3139 if (helper->user_callback) {
3141 /* This is not a GDK lock because we are a Tinymail callback and
3142 * Tinymail already acquires the Gdk lock */
3143 helper->user_callback (self, folder, helper->user_data);
3147 g_slice_free (RefreshAsyncHelper, helper);
3149 /* Notify about operation end */
3150 modest_mail_operation_notify_end (self);
3151 g_object_unref(self);
3155 on_refresh_folder_status_update (GObject *obj,
3159 RefreshAsyncHelper *helper = NULL;
3160 ModestMailOperation *self = NULL;
3161 ModestMailOperationPrivate *priv = NULL;
3162 ModestMailOperationState *state;
3164 g_return_if_fail (user_data != NULL);
3165 g_return_if_fail (status != NULL);
3167 /* Show only the status information we want */
3168 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3171 helper = (RefreshAsyncHelper *) user_data;
3172 self = helper->mail_op;
3173 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3177 priv->done = status->position;
3178 priv->total = status->of_total;
3180 state = modest_mail_operation_clone_state (self);
3182 /* This is not a GDK lock because we are a Tinymail callback and
3183 * Tinymail already acquires the Gdk lock */
3184 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3186 g_slice_free (ModestMailOperationState, state);
3190 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3192 RefreshAsyncUserCallback user_callback,
3195 ModestMailOperationPrivate *priv = NULL;
3196 RefreshAsyncHelper *helper = NULL;
3198 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3200 /* Check memory low */
3201 if (_check_memory_low (self)) {
3203 user_callback (self, folder, user_data);
3204 /* Notify about operation end */
3205 modest_mail_operation_notify_end (self);
3209 /* Get account and set it into mail_operation */
3210 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3211 priv->account = modest_tny_folder_get_account (folder);
3212 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3214 /* Create the helper */
3215 helper = g_slice_new0 (RefreshAsyncHelper);
3216 helper->mail_op = g_object_ref(self);
3217 helper->user_callback = user_callback;
3218 helper->user_data = user_data;
3220 modest_mail_operation_notify_start (self);
3222 /* notify that the operation was started */
3223 ModestMailOperationState *state;
3224 state = modest_mail_operation_clone_state (self);
3227 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3229 g_slice_free (ModestMailOperationState, state);
3231 tny_folder_refresh_async (folder,
3233 on_refresh_folder_status_update,
3238 run_queue_stop (ModestTnySendQueue *queue,
3239 ModestMailOperation *self)
3241 ModestMailOperationPrivate *priv;
3243 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3244 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3247 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3249 modest_mail_operation_notify_end (self);
3250 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3251 g_object_unref (self);
3254 modest_mail_operation_run_queue (ModestMailOperation *self,
3255 ModestTnySendQueue *queue)
3257 ModestMailOperationPrivate *priv;
3259 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3260 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3261 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3263 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3264 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3265 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3267 modest_mail_operation_notify_start (self);
3268 g_object_ref (self);
3269 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3273 sync_folder_finish_callback (TnyFolder *self,
3279 ModestMailOperation *mail_op;
3280 ModestMailOperationPrivate *priv;
3282 mail_op = (ModestMailOperation *) user_data;
3283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3285 /* If canceled by the user, ignore the error given by Tinymail */
3287 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3289 /* If the operation was a sync then the status is
3290 failed, but if it's part of another operation then
3291 just set it as finished with errors */
3292 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3293 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3295 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3296 priv->error = g_error_copy ((const GError *) err);
3297 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3299 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3302 modest_mail_operation_notify_end (mail_op);
3303 g_object_unref (mail_op);
3307 modest_mail_operation_sync_folder (ModestMailOperation *self,
3308 TnyFolder *folder, gboolean expunge)
3310 ModestMailOperationPrivate *priv;
3312 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3313 g_return_if_fail (TNY_IS_FOLDER (folder));
3314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3316 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3317 priv->account = modest_tny_folder_get_account (folder);
3318 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3320 modest_mail_operation_notify_start (self);
3321 g_object_ref (self);
3322 tny_folder_sync_async (folder, expunge,
3323 (TnyFolderCallback) sync_folder_finish_callback,
3328 modest_mail_operation_notify_start (ModestMailOperation *self)
3330 ModestMailOperationPrivate *priv = NULL;
3332 g_return_if_fail (self);
3334 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3336 /* Ensure that all the fields are filled correctly */
3337 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3339 /* Notify the observers about the mail operation. We do not
3340 wrapp this emission because we assume that this function is
3341 always called from within the main lock */
3342 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3347 * It's used by the mail operation queue to notify the observers
3348 * attached to that signal that the operation finished. We need to use
3349 * that because tinymail does not give us the progress of a given
3350 * operation when it finishes (it directly calls the operation
3354 modest_mail_operation_notify_end (ModestMailOperation *self)
3356 ModestMailOperationPrivate *priv = NULL;
3358 g_return_if_fail (self);
3360 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3362 /* Notify the observers about the mail operation end. We do
3363 not wrapp this emission because we assume that this
3364 function is always called from within the main lock */
3365 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3367 /* Remove the error user data */
3368 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3369 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3373 modest_mail_operation_get_account (ModestMailOperation *self)
3375 ModestMailOperationPrivate *priv = NULL;
3377 g_return_val_if_fail (self, NULL);
3379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3381 return (priv->account) ? g_object_ref (priv->account) : NULL;
3385 modest_mail_operation_noop (ModestMailOperation *self)
3387 ModestMailOperationPrivate *priv = NULL;
3389 g_return_if_fail (self);
3391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3392 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3393 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3397 /* This mail operation does nothing actually */
3398 modest_mail_operation_notify_start (self);
3399 modest_mail_operation_notify_end (self);
3404 modest_mail_operation_to_string (ModestMailOperation *self)
3406 const gchar *type, *status, *account_id;
3407 ModestMailOperationPrivate *priv = NULL;
3409 g_return_val_if_fail (self, NULL);
3411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3413 /* new operations don't have anything interesting */
3414 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3415 return g_strdup_printf ("%p <new operation>", self);
3417 switch (priv->op_type) {
3418 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3419 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3420 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3421 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3422 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3423 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3424 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3425 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3426 default: type = "UNEXPECTED"; break;
3429 switch (priv->status) {
3430 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3431 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3432 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3433 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3434 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3435 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3436 default: status= "UNEXPECTED"; break;
3439 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3441 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3442 priv->done, priv->total,
3443 priv->error && priv->error->message ? priv->error->message : "");
3447 * Once the mail operations were objects this will be no longer
3448 * needed. I don't like it, but we need it for the moment
3451 _check_memory_low (ModestMailOperation *mail_op)
3453 if (modest_platform_check_memory_low (NULL, FALSE)) {
3454 ModestMailOperationPrivate *priv;
3456 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3457 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3458 g_set_error (&(priv->error),
3459 MODEST_MAIL_OPERATION_ERROR,
3460 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3461 "Not enough memory to complete the operation");