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-error.h>
45 #include <tny-folder-observer.h>
46 #include <camel/camel-stream-mem.h>
47 #include <glib/gi18n.h>
48 #include "modest-platform.h"
49 #include "modest-account-mgr-helpers.h"
50 #include <modest-tny-account.h>
51 #include <modest-tny-send-queue.h>
52 #include <modest-runtime.h>
53 #include "modest-text-utils.h"
54 #include "modest-tny-msg.h"
55 #include "modest-tny-folder.h"
56 #include "modest-tny-account-store.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-marshal.h"
59 #include "modest-error.h"
60 #include "modest-mail-operation.h"
61 #include <modest-count-stream.h>
62 #include <libgnomevfs/gnome-vfs.h>
63 #include "modest-utils.h"
64 #include "modest-debug.h"
69 * Remove all these #ifdef stuff when the tinymail's idle calls become
72 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
74 /* 'private'/'protected' functions */
75 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
76 static void modest_mail_operation_init (ModestMailOperation *obj);
77 static void modest_mail_operation_finalize (GObject *obj);
79 static void get_msg_async_cb (TnyFolder *folder,
85 static void get_msg_status_cb (GObject *obj,
89 static void modest_mail_operation_notify_start (ModestMailOperation *self);
90 static void modest_mail_operation_notify_end (ModestMailOperation *self);
92 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
94 gint *last_total_bytes,
95 gint *sum_total_bytes,
97 gboolean increment_done);
99 static guint compute_message_list_size (TnyList *headers, guint num_elements);
101 static int compare_headers_by_date (gconstpointer a,
104 static void sync_folder_finish_callback (TnyFolder *self,
109 static gboolean _check_memory_low (ModestMailOperation *mail_op);
113 ModestTnySendQueue *queue;
114 ModestMailOperation *self;
120 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
121 ModestMailOperationStatus status);
123 /* Helpers for the update account operation (send & receive)*/
126 ModestMailOperation *mail_op;
128 UpdateAccountCallback callback;
133 TnyFolderObserver *inbox_observer;
134 RetrieveAllCallback retrieve_all_cb;
135 gboolean interactive;
139 static void destroy_update_account_info (UpdateAccountInfo *info);
141 static void update_account_send_mail (UpdateAccountInfo *info);
143 static void update_account_get_msg_async_cb (TnyFolder *folder,
149 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
150 TnyList *new_headers);
152 enum _ModestMailOperationSignals
154 PROGRESS_CHANGED_SIGNAL,
155 OPERATION_STARTED_SIGNAL,
156 OPERATION_FINISHED_SIGNAL,
160 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
161 struct _ModestMailOperationPrivate {
167 ErrorCheckingUserCallback error_checking;
168 gpointer error_checking_user_data;
169 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
170 ModestMailOperationStatus status;
171 ModestMailOperationTypeOperation op_type;
174 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
175 MODEST_TYPE_MAIL_OPERATION, \
176 ModestMailOperationPrivate))
178 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
179 priv->status = new_status;\
184 GetMsgAsyncUserCallback user_callback;
186 TnyIterator *more_msgs;
188 ModestMailOperation *mail_op;
189 GDestroyNotify destroy_notify;
190 gint last_total_bytes;
191 gint sum_total_bytes;
195 typedef struct _RefreshAsyncHelper {
196 ModestMailOperation *mail_op;
197 RefreshAsyncUserCallback user_callback;
199 } RefreshAsyncHelper;
201 typedef struct _XFerMsgsAsyncHelper
203 ModestMailOperation *mail_op;
205 TnyIterator *more_msgs;
206 TnyFolder *dest_folder;
207 XferMsgsAsyncUserCallback user_callback;
210 gint last_total_bytes;
211 gint sum_total_bytes;
213 } XFerMsgsAsyncHelper;
215 typedef struct _XFerFolderAsyncHelper
217 ModestMailOperation *mail_op;
218 XferFolderAsyncUserCallback user_callback;
220 } XFerFolderAsyncHelper;
222 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
226 static void modest_mail_operation_create_msg (ModestMailOperation *self,
227 const gchar *from, const gchar *to,
228 const gchar *cc, const gchar *bcc,
229 const gchar *subject, const gchar *plain_body,
230 const gchar *html_body, const GList *attachments_list,
231 const GList *images_list,
232 TnyHeaderFlags priority_flags,
233 ModestMailOperationCreateMsgCallback callback,
236 static gboolean idle_notify_queue (gpointer data);
239 ModestMailOperation *mail_op;
247 GList *attachments_list;
249 TnyHeaderFlags priority_flags;
250 ModestMailOperationCreateMsgCallback callback;
256 ModestMailOperation *mail_op;
258 ModestMailOperationCreateMsgCallback callback;
263 static GObjectClass *parent_class = NULL;
265 static guint signals[NUM_SIGNALS] = {0};
268 modest_mail_operation_get_type (void)
270 static GType my_type = 0;
272 static const GTypeInfo my_info = {
273 sizeof(ModestMailOperationClass),
274 NULL, /* base init */
275 NULL, /* base finalize */
276 (GClassInitFunc) modest_mail_operation_class_init,
277 NULL, /* class finalize */
278 NULL, /* class data */
279 sizeof(ModestMailOperation),
281 (GInstanceInitFunc) modest_mail_operation_init,
284 my_type = g_type_register_static (G_TYPE_OBJECT,
285 "ModestMailOperation",
292 modest_mail_operation_class_init (ModestMailOperationClass *klass)
294 GObjectClass *gobject_class;
295 gobject_class = (GObjectClass*) klass;
297 parent_class = g_type_class_peek_parent (klass);
298 gobject_class->finalize = modest_mail_operation_finalize;
300 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
303 * ModestMailOperation::progress-changed
304 * @self: the #MailOperation that emits the signal
305 * @user_data: user data set when the signal handler was connected
307 * Emitted when the progress of a mail operation changes
309 signals[PROGRESS_CHANGED_SIGNAL] =
310 g_signal_new ("progress-changed",
311 G_TYPE_FROM_CLASS (gobject_class),
313 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
315 g_cclosure_marshal_VOID__POINTER,
316 G_TYPE_NONE, 1, G_TYPE_POINTER);
320 * This signal is issued whenever a mail operation starts, and
321 * starts mean when the tinymail operation is issued. This
322 * means that it could happen that something wrong happens and
323 * the tinymail function is never called. In this situation a
324 * operation-finished will be issued without any
327 signals[OPERATION_STARTED_SIGNAL] =
328 g_signal_new ("operation-started",
329 G_TYPE_FROM_CLASS (gobject_class),
331 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
333 g_cclosure_marshal_VOID__VOID,
338 * This signal is issued whenever a mail operation
339 * finishes. Note that this signal could be issued without any
340 * previous "operation-started" signal, because this last one
341 * is only issued when the tinymail operation is successfully
344 signals[OPERATION_FINISHED_SIGNAL] =
345 g_signal_new ("operation-finished",
346 G_TYPE_FROM_CLASS (gobject_class),
348 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
350 g_cclosure_marshal_VOID__VOID,
355 modest_mail_operation_init (ModestMailOperation *obj)
357 ModestMailOperationPrivate *priv;
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
361 priv->account = NULL;
362 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
363 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
368 priv->error_checking = NULL;
369 priv->error_checking_user_data = NULL;
373 modest_mail_operation_finalize (GObject *obj)
375 ModestMailOperationPrivate *priv;
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
382 g_error_free (priv->error);
386 g_object_unref (priv->source);
390 g_object_unref (priv->account);
391 priv->account = NULL;
395 G_OBJECT_CLASS(parent_class)->finalize (obj);
399 modest_mail_operation_new (GObject *source)
401 ModestMailOperation *obj;
402 ModestMailOperationPrivate *priv;
404 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
408 priv->source = g_object_ref(source);
414 modest_mail_operation_new_with_error_handling (GObject *source,
415 ErrorCheckingUserCallback error_handler,
417 ErrorCheckingUserDataDestroyer error_handler_destroyer)
419 ModestMailOperation *obj;
420 ModestMailOperationPrivate *priv;
422 obj = modest_mail_operation_new (source);
423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
425 g_return_val_if_fail (error_handler != NULL, obj);
426 priv->error_checking = error_handler;
427 priv->error_checking_user_data = user_data;
428 priv->error_checking_user_data_destroyer = error_handler_destroyer;
434 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
436 ModestMailOperationPrivate *priv;
438 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
440 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
441 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
443 /* Call the user callback */
444 if (priv->error_checking != NULL)
445 priv->error_checking (self, priv->error_checking_user_data);
449 ModestMailOperationTypeOperation
450 modest_mail_operation_get_type_operation (ModestMailOperation *self)
452 ModestMailOperationPrivate *priv;
454 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
455 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 return priv->op_type;
463 modest_mail_operation_is_mine (ModestMailOperation *self,
466 ModestMailOperationPrivate *priv;
468 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
471 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
472 if (priv->source == NULL) return FALSE;
474 return priv->source == me;
478 modest_mail_operation_get_source (ModestMailOperation *self)
480 ModestMailOperationPrivate *priv;
482 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
485 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
487 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
491 return (priv->source) ? g_object_ref (priv->source) : NULL;
494 ModestMailOperationStatus
495 modest_mail_operation_get_status (ModestMailOperation *self)
497 ModestMailOperationPrivate *priv;
499 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
500 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
501 MODEST_MAIL_OPERATION_STATUS_INVALID);
503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
505 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
506 return MODEST_MAIL_OPERATION_STATUS_INVALID;
513 modest_mail_operation_get_error (ModestMailOperation *self)
515 ModestMailOperationPrivate *priv;
517 g_return_val_if_fail (self, NULL);
518 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
531 modest_mail_operation_cancel (ModestMailOperation *self)
533 ModestMailOperationPrivate *priv;
534 gboolean canceled = FALSE;
536 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
538 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
541 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
543 /* Cancel the mail operation */
544 g_return_val_if_fail (priv->account, FALSE);
545 tny_account_cancel (priv->account);
547 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
548 ModestTnySendQueue *queue;
549 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
552 /* Cancel the sending of the following next messages */
553 if (TNY_IS_SEND_QUEUE (queue))
554 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
561 modest_mail_operation_get_task_done (ModestMailOperation *self)
563 ModestMailOperationPrivate *priv;
565 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
568 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
573 modest_mail_operation_get_task_total (ModestMailOperation *self)
575 ModestMailOperationPrivate *priv;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
585 modest_mail_operation_is_finished (ModestMailOperation *self)
587 ModestMailOperationPrivate *priv;
588 gboolean retval = FALSE;
590 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
595 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
596 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
597 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
598 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
608 * Creates an image of the current state of a mail operation, the
609 * caller must free it
611 static ModestMailOperationState *
612 modest_mail_operation_clone_state (ModestMailOperation *self)
614 ModestMailOperationState *state;
615 ModestMailOperationPrivate *priv;
617 g_return_val_if_fail (self, NULL);
618 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
619 g_return_val_if_fail (priv, NULL);
624 state = g_slice_new (ModestMailOperationState);
626 state->status = priv->status;
627 state->op_type = priv->op_type;
628 state->done = priv->done;
629 state->total = priv->total;
630 state->finished = modest_mail_operation_is_finished (self);
631 state->bytes_done = 0;
632 state->bytes_total = 0;
637 /* ******************************************************************* */
638 /* ************************** SEND ACTIONS ************************* */
639 /* ******************************************************************* */
643 ModestMailOperation *mail_op;
648 send_mail_on_sync_async_cb (TnyFolder *folder,
653 ModestMailOperationPrivate *priv;
654 ModestMailOperation *self;
655 SendNewMailHelper *helper;
657 helper = (SendNewMailHelper *) user_data;
658 self = helper->mail_op;
659 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
661 if (cancelled || err)
665 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
666 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
667 "Error adding a msg to the send queue\n");
668 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
670 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
675 modest_mail_operation_notify_end (self);
677 g_object_unref (helper->mail_op);
678 g_slice_free (SendNewMailHelper, helper);
682 run_queue_start (TnySendQueue *self,
685 RunQueueHelper *helper = (RunQueueHelper *) user_data;
686 ModestMailOperation *mail_op;
688 g_debug ("%s sending queue successfully started", __FUNCTION__);
690 /* Wait for the message to be sent */
691 mail_op = modest_mail_operation_new (NULL);
692 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
694 modest_mail_operation_run_queue (mail_op, helper->queue);
695 g_object_unref (mail_op);
697 /* Free the helper and end operation */
698 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
702 run_queue_error_happened (TnySendQueue *queue,
708 RunQueueHelper *helper = (RunQueueHelper *) user_data;
709 ModestMailOperationPrivate *priv;
711 /* If we are here this means that the send queue could not
712 start to send emails. Shouldn't happen as this means that
713 we could not create the thread */
714 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
716 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
717 priv->error = g_error_copy ((const GError *) error);
719 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
720 /* This code is here for safety reasons. It should
721 never be called, because that would mean that we
722 are not controlling some error case */
723 g_warning ("%s Error %s should not happen",
724 __FUNCTION__, error->message);
727 /* Free helper and end operation */
728 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
732 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
738 ModestMailOperationPrivate *priv;
739 ModestMailOperation *self;
740 SendNewMailHelper *helper;
742 helper = (SendNewMailHelper *) user_data;
743 self = helper->mail_op;
744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
746 if (cancelled || err)
750 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
751 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
752 "Error adding a msg to the send queue\n");
753 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
755 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
759 if (helper->notify) {
760 TnyTransportAccount *trans_account;
761 ModestTnySendQueue *queue;
763 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
764 queue = modest_runtime_get_send_queue (trans_account, TRUE);
766 RunQueueHelper *helper;
768 /* Create the helper */
769 helper = g_slice_new0 (RunQueueHelper);
770 helper->queue = g_object_ref (queue);
771 helper->self = g_object_ref (self);
773 /* if sending is ongoing wait for the queue to
774 stop. Otherwise wait for the queue-start
775 signal. It could happen that the queue
776 could not start, then check also the error
778 if (modest_tny_send_queue_sending_in_progress (queue)) {
779 run_queue_start (TNY_SEND_QUEUE (queue), helper);
781 helper->start_handler = g_signal_connect (queue, "queue-start",
782 G_CALLBACK (run_queue_start),
784 helper->error_handler = g_signal_connect (queue, "error-happened",
785 G_CALLBACK (run_queue_error_happened),
789 /* Finalize this mail operation */
790 modest_mail_operation_notify_end (self);
792 g_object_unref (trans_account);
795 g_object_unref (helper->mail_op);
796 g_slice_free (SendNewMailHelper, helper);
800 idle_create_msg_cb (gpointer idle_data)
802 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
804 /* This is a GDK lock because we are an idle callback and
805 * info->callback can contain Gtk+ code */
807 gdk_threads_enter (); /* CHECKED */
808 info->callback (info->mail_op, info->msg, info->userdata);
810 g_object_unref (info->mail_op);
812 g_object_unref (info->msg);
813 g_slice_free (CreateMsgIdleInfo, info);
814 gdk_threads_leave (); /* CHECKED */
820 create_msg_thread (gpointer thread_data)
822 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
823 TnyMsg *new_msg = NULL;
824 ModestMailOperationPrivate *priv;
827 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
828 if (info->html_body == NULL) {
829 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
830 info->bcc, info->subject, info->plain_body,
831 info->attachments_list, &attached,
834 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
835 info->bcc, info->subject, info->html_body,
836 info->plain_body, info->attachments_list,
837 info->images_list, &attached,
844 /* Set priority flags in message */
845 header = tny_msg_get_header (new_msg);
846 tny_header_set_flag (header, info->priority_flags);
848 /* Set attachment flags in message */
849 if (info->attachments_list != NULL && attached > 0)
850 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
852 g_object_unref (G_OBJECT(header));
854 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
856 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
857 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
858 "modest: failed to create a new msg\n");
866 g_free (info->plain_body);
867 g_free (info->html_body);
868 g_free (info->subject);
869 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
870 g_list_free (info->attachments_list);
871 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
872 g_list_free (info->images_list);
874 if (info->callback) {
875 CreateMsgIdleInfo *idle_info;
876 idle_info = g_slice_new0 (CreateMsgIdleInfo);
877 idle_info->mail_op = g_object_ref (info->mail_op);
878 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
879 idle_info->callback = info->callback;
880 idle_info->userdata = info->userdata;
881 g_idle_add (idle_create_msg_cb, idle_info);
883 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
886 g_object_unref (info->mail_op);
887 g_slice_free (CreateMsgInfo, info);
888 if (new_msg) g_object_unref(new_msg);
894 modest_mail_operation_create_msg (ModestMailOperation *self,
895 const gchar *from, const gchar *to,
896 const gchar *cc, const gchar *bcc,
897 const gchar *subject, const gchar *plain_body,
898 const gchar *html_body,
899 const GList *attachments_list,
900 const GList *images_list,
901 TnyHeaderFlags priority_flags,
902 ModestMailOperationCreateMsgCallback callback,
905 CreateMsgInfo *info = NULL;
907 info = g_slice_new0 (CreateMsgInfo);
908 info->mail_op = g_object_ref (self);
910 info->from = g_strdup (from);
911 info->to = g_strdup (to);
912 info->cc = g_strdup (cc);
913 info->bcc = g_strdup (bcc);
914 info->subject = g_strdup (subject);
915 info->plain_body = g_strdup (plain_body);
916 info->html_body = g_strdup (html_body);
917 info->attachments_list = g_list_copy ((GList *) attachments_list);
918 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
919 info->images_list = g_list_copy ((GList *) images_list);
920 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
921 info->priority_flags = priority_flags;
923 info->callback = callback;
924 info->userdata = userdata;
926 g_thread_create (create_msg_thread, info, FALSE, NULL);
931 TnyTransportAccount *transport_account;
936 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
940 TnySendQueue *send_queue = NULL;
941 ModestMailOperationPrivate *priv = NULL;
942 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
943 TnyFolder *draft_folder = NULL;
944 TnyFolder *outbox_folder = NULL;
945 TnyHeader *header = NULL;
947 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
950 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
951 modest_mail_operation_notify_end (self);
955 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
956 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
957 modest_mail_operation_notify_end (self);
961 /* Add message to send queue */
962 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
963 if (!TNY_IS_SEND_QUEUE(send_queue)) {
965 g_error_free (priv->error);
968 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
969 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
970 "modest: could not find send queue for account\n");
971 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
972 modest_mail_operation_notify_end (self);
975 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
976 helper->mail_op = g_object_ref (self);
977 helper->notify = (info->draft_msg == NULL);
979 /* Add the msg to the queue. The callback will free
981 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
983 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
987 if (info->draft_msg != NULL) {
988 TnyList *tmp_headers = NULL;
989 TnyFolder *folder = NULL;
990 TnyFolder *src_folder = NULL;
991 TnyFolderType folder_type;
992 TnyTransportAccount *transport_account = NULL;
993 SendNewMailHelper *helper = NULL;
995 /* To remove the old mail from its source folder, we need to get the
996 * transport account of the original draft message (the transport account
997 * might have been changed by the user) */
998 header = tny_msg_get_header (info->draft_msg);
999 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1000 modest_runtime_get_account_store(), header);
1001 if (transport_account == NULL)
1002 transport_account = g_object_ref(info->transport_account);
1003 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1004 TNY_FOLDER_TYPE_DRAFTS);
1005 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1006 TNY_FOLDER_TYPE_OUTBOX);
1007 g_object_unref(transport_account);
1009 if (!draft_folder) {
1010 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1012 modest_mail_operation_notify_end (self);
1015 if (!outbox_folder) {
1016 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1018 modest_mail_operation_notify_end (self);
1022 folder = tny_msg_get_folder (info->draft_msg);
1023 if (folder == NULL) {
1024 modest_mail_operation_notify_end (self);
1027 folder_type = modest_tny_folder_guess_folder_type (folder);
1029 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1030 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1032 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1033 src_folder = outbox_folder;
1035 src_folder = draft_folder;
1037 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1038 * because this function requires it to have a UID. */
1039 helper = g_slice_new (SendNewMailHelper);
1040 helper->mail_op = g_object_ref (self);
1041 helper->notify = TRUE;
1043 tmp_headers = tny_simple_list_new ();
1044 tny_list_append (tmp_headers, (GObject*) header);
1045 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1046 g_object_unref (tmp_headers);
1047 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1049 g_object_unref (folder);
1054 g_object_unref (header);
1055 if (info->draft_msg)
1056 g_object_unref (info->draft_msg);
1058 g_object_unref (draft_folder);
1060 g_object_unref (outbox_folder);
1061 if (info->transport_account)
1062 g_object_unref (info->transport_account);
1063 g_slice_free (SendNewMailInfo, info);
1067 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1068 TnyTransportAccount *transport_account,
1070 const gchar *from, const gchar *to,
1071 const gchar *cc, const gchar *bcc,
1072 const gchar *subject, const gchar *plain_body,
1073 const gchar *html_body,
1074 const GList *attachments_list,
1075 const GList *images_list,
1076 TnyHeaderFlags priority_flags)
1078 ModestMailOperationPrivate *priv = NULL;
1079 SendNewMailInfo *info;
1081 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1082 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1084 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1085 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1086 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1087 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1089 modest_mail_operation_notify_start (self);
1091 /* Check parametters */
1093 /* Set status failed and set an error */
1094 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1095 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1096 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1097 _("Error trying to send a mail. You need to set at least one recipient"));
1098 modest_mail_operation_notify_end (self);
1101 info = g_slice_new0 (SendNewMailInfo);
1102 info->transport_account = transport_account;
1103 if (transport_account)
1104 g_object_ref (transport_account);
1105 info->draft_msg = draft_msg;
1107 g_object_ref (draft_msg);
1110 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1111 attachments_list, images_list, priority_flags,
1112 modest_mail_operation_send_new_mail_cb, info);
1118 TnyTransportAccount *transport_account;
1120 SaveToDraftstCallback callback;
1124 ModestMailOperation *mailop;
1125 } SaveToDraftsAddMsgInfo;
1128 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1133 ModestMailOperationPrivate *priv = NULL;
1134 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1135 GError *io_error = NULL;
1137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1139 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1140 io_error = priv->error;
1144 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1145 g_error_free(priv->error);
1148 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1150 if ((!priv->error) && (info->draft_msg != NULL)) {
1151 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1152 TnyFolder *src_folder = tny_header_get_folder (header);
1154 g_debug ("--- REMOVE AND SYNC");
1155 /* Remove the old draft */
1156 tny_folder_remove_msg (src_folder, header, NULL);
1158 /* Synchronize to expunge and to update the msg counts */
1159 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1160 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1161 g_debug ("--- REMOVED - SYNCED");
1163 g_object_unref (G_OBJECT(header));
1164 g_object_unref (G_OBJECT(src_folder));
1168 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1170 g_error_free (io_error);
1173 } else if (io_error) {
1174 priv->error = io_error;
1175 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1177 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1180 /* Call the user callback */
1182 info->callback (info->mailop, info->msg, info->user_data);
1184 if (info->transport_account)
1185 g_object_unref (G_OBJECT(info->transport_account));
1186 if (info->draft_msg)
1187 g_object_unref (G_OBJECT (info->draft_msg));
1189 g_object_unref (G_OBJECT(info->drafts));
1191 g_object_unref (G_OBJECT (info->msg));
1193 modest_mail_operation_notify_end (info->mailop);
1194 g_object_unref(info->mailop);
1195 g_slice_free (SaveToDraftsAddMsgInfo, info);
1200 TnyTransportAccount *transport_account;
1202 SaveToDraftstCallback callback;
1207 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1211 TnyFolder *drafts = NULL;
1212 ModestMailOperationPrivate *priv = NULL;
1213 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1215 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1218 if (!(priv->error)) {
1219 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1220 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1221 "modest: failed to create a new msg\n");
1224 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1225 TNY_FOLDER_TYPE_DRAFTS);
1226 if (!drafts && !(priv->error)) {
1227 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1228 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1229 "modest: failed to create a new msg\n");
1233 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1234 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1235 cb_info->transport_account = g_object_ref(info->transport_account);
1236 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1237 cb_info->callback = info->callback;
1238 cb_info->user_data = info->user_data;
1239 cb_info->drafts = g_object_ref(drafts);
1240 cb_info->msg = g_object_ref(msg);
1241 cb_info->mailop = g_object_ref(self);
1242 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1245 /* Call the user callback */
1246 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1248 info->callback (self, msg, info->user_data);
1249 modest_mail_operation_notify_end (self);
1253 g_object_unref (G_OBJECT(drafts));
1254 if (info->draft_msg)
1255 g_object_unref (G_OBJECT (info->draft_msg));
1256 if (info->transport_account)
1257 g_object_unref (G_OBJECT(info->transport_account));
1258 g_slice_free (SaveToDraftsInfo, info);
1262 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1263 TnyTransportAccount *transport_account,
1265 const gchar *from, const gchar *to,
1266 const gchar *cc, const gchar *bcc,
1267 const gchar *subject, const gchar *plain_body,
1268 const gchar *html_body,
1269 const GList *attachments_list,
1270 const GList *images_list,
1271 TnyHeaderFlags priority_flags,
1272 SaveToDraftstCallback callback,
1275 ModestMailOperationPrivate *priv = NULL;
1276 SaveToDraftsInfo *info = NULL;
1278 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1279 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1281 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1283 /* Get account and set it into mail_operation */
1284 priv->account = g_object_ref (transport_account);
1285 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1287 info = g_slice_new0 (SaveToDraftsInfo);
1288 info->transport_account = g_object_ref (transport_account);
1289 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1290 info->callback = callback;
1291 info->user_data = user_data;
1293 g_debug ("--- CREATE MESSAGE");
1294 modest_mail_operation_notify_start (self);
1295 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1296 attachments_list, images_list, priority_flags,
1297 modest_mail_operation_save_to_drafts_cb, info);
1302 ModestMailOperation *mail_op;
1303 TnyMimePart *mime_part;
1305 GetMimePartSizeCallback callback;
1307 } GetMimePartSizeInfo;
1309 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1310 /* We use this folder observer to track the headers that have been
1311 * added to a folder */
1314 TnyList *new_headers;
1315 } InternalFolderObserver;
1318 GObjectClass parent;
1319 } InternalFolderObserverClass;
1321 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1323 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1324 internal_folder_observer,
1326 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1330 foreach_add_item (gpointer header, gpointer user_data)
1332 tny_list_prepend (TNY_LIST (user_data),
1336 /* This is the method that looks for new messages in a folder */
1338 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1340 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1342 TnyFolderChangeChanged changed;
1344 changed = tny_folder_change_get_changed (change);
1346 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1349 /* Get added headers */
1350 list = tny_simple_list_new ();
1351 tny_folder_change_get_added_headers (change, list);
1353 /* Add them to the folder observer */
1354 tny_list_foreach (list, foreach_add_item,
1355 derived->new_headers);
1357 g_object_unref (G_OBJECT (list));
1362 internal_folder_observer_init (InternalFolderObserver *self)
1364 self->new_headers = tny_simple_list_new ();
1367 internal_folder_observer_finalize (GObject *object)
1369 InternalFolderObserver *self;
1371 self = (InternalFolderObserver *) object;
1372 g_object_unref (self->new_headers);
1374 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1377 tny_folder_observer_init (TnyFolderObserverIface *iface)
1379 iface->update = internal_folder_observer_update;
1382 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1384 GObjectClass *object_class;
1386 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1387 object_class = (GObjectClass*) klass;
1388 object_class->finalize = internal_folder_observer_finalize;
1392 destroy_update_account_info (UpdateAccountInfo *info)
1394 g_free (info->account_name);
1395 g_object_unref (info->folders);
1396 g_object_unref (info->mail_op);
1397 g_slice_free (UpdateAccountInfo, info);
1402 update_account_send_mail (UpdateAccountInfo *info)
1404 TnyTransportAccount *transport_account = NULL;
1405 ModestTnyAccountStore *account_store;
1407 account_store = modest_runtime_get_account_store ();
1409 /* We don't try to send messages while sending mails is blocked */
1410 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1413 /* Get the transport account */
1414 transport_account = (TnyTransportAccount *)
1415 modest_tny_account_store_get_transport_account_for_open_connection (account_store,
1416 info->account_name);
1418 if (transport_account) {
1419 ModestTnySendQueue *send_queue;
1423 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1424 g_object_unref (transport_account);
1426 if (TNY_IS_SEND_QUEUE (send_queue)) {
1427 /* Get outbox folder */
1428 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1429 if (outbox) { /* this could fail in some cases */
1430 num_messages = tny_folder_get_all_count (outbox);
1431 g_object_unref (outbox);
1433 g_warning ("%s: could not get outbox", __FUNCTION__);
1437 if (num_messages != 0) {
1438 /* Reenable suspended items */
1439 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1442 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1443 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1451 update_account_get_msg_async_cb (TnyFolder *folder,
1457 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1458 ModestMailOperationPrivate *priv;
1460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1463 if (TNY_IS_MSG (msg)) {
1464 TnyHeader *header = tny_msg_get_header (msg);
1467 ModestMailOperationState *state;
1468 state = modest_mail_operation_clone_state (msg_info->mail_op);
1469 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1470 state->bytes_done = msg_info->sum_total_bytes;
1471 state->bytes_total = msg_info->total_bytes;
1473 /* Notify the status change. Only notify about changes
1474 referred to bytes */
1475 g_signal_emit (G_OBJECT (msg_info->mail_op),
1476 signals[PROGRESS_CHANGED_SIGNAL],
1479 g_object_unref (header);
1480 g_slice_free (ModestMailOperationState, state);
1484 if (priv->done == priv->total) {
1485 TnyList *new_headers;
1486 UpdateAccountInfo *info;
1488 /* After getting all the messages send the ones in the
1490 info = (UpdateAccountInfo *) msg_info->user_data;
1491 update_account_send_mail (info);
1493 /* Check if the operation was a success */
1495 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1497 /* Call the user callback and free */
1498 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1499 update_account_notify_user_and_free (info, new_headers);
1500 g_object_unref (new_headers);
1502 /* Delete the helper */
1503 g_object_unref (msg_info->more_msgs);
1504 g_object_unref (msg_info->mail_op);
1505 g_slice_free (GetMsgInfo, msg_info);
1510 update_account_notify_user_and_free (UpdateAccountInfo *info,
1511 TnyList *new_headers)
1513 /* Set the account back to not busy */
1514 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1515 info->account_name, FALSE);
1519 info->callback (info->mail_op, new_headers, info->user_data);
1521 /* Mail operation end */
1522 modest_mail_operation_notify_end (info->mail_op);
1526 g_object_unref (new_headers);
1527 destroy_update_account_info (info);
1531 inbox_refreshed_cb (TnyFolder *inbox,
1536 UpdateAccountInfo *info;
1537 ModestMailOperationPrivate *priv;
1538 TnyIterator *new_headers_iter;
1539 GPtrArray *new_headers_array = NULL;
1540 gint max_size, retrieve_limit, i;
1541 ModestAccountMgr *mgr;
1542 ModestAccountRetrieveType retrieve_type;
1543 TnyList *new_headers = NULL;
1544 gboolean headers_only, ignore_limit;
1546 info = (UpdateAccountInfo *) user_data;
1547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1548 mgr = modest_runtime_get_account_mgr ();
1550 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1551 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1553 if (canceled || err) {
1554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1556 priv->error = g_error_copy (err);
1558 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1559 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1562 tny_folder_remove_observer (inbox, info->inbox_observer);
1563 g_object_unref (info->inbox_observer);
1564 info->inbox_observer = NULL;
1566 /* Notify the user about the error and then exit */
1567 update_account_notify_user_and_free (info, NULL);
1572 /* Try to send anyway */
1576 /* Get the message max size */
1577 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1578 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1580 max_size = G_MAXINT;
1582 max_size = max_size * KB;
1584 /* Create the new headers array. We need it to sort the
1585 new headers by date */
1586 new_headers_array = g_ptr_array_new ();
1587 if (info->inbox_observer) {
1588 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1589 while (!tny_iterator_is_done (new_headers_iter)) {
1590 TnyHeader *header = NULL;
1592 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1593 /* Apply per-message size limits */
1594 if (tny_header_get_message_size (header) < max_size)
1595 g_ptr_array_add (new_headers_array, g_object_ref (header));
1597 g_object_unref (header);
1598 tny_iterator_next (new_headers_iter);
1600 g_object_unref (new_headers_iter);
1602 tny_folder_remove_observer (inbox, info->inbox_observer);
1603 g_object_unref (info->inbox_observer);
1604 info->inbox_observer = NULL;
1607 if (new_headers_array->len == 0) {
1608 g_ptr_array_free (new_headers_array, FALSE);
1612 /* Get per-account message amount retrieval limit */
1613 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1614 if (retrieve_limit == 0)
1615 retrieve_limit = G_MAXINT;
1617 /* Get per-account retrieval type */
1618 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1619 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1622 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1624 /* Ask the users if they want to retrieve all the messages
1625 even though the limit was exceeded */
1626 ignore_limit = FALSE;
1627 if (new_headers_array->len > retrieve_limit) {
1628 /* Ask the user if a callback has been specified and
1629 if the mail operation has a source (this means that
1630 was invoked by the user and not automatically by a
1632 if (info->retrieve_all_cb && priv->source)
1633 ignore_limit = info->retrieve_all_cb (priv->source,
1634 new_headers_array->len,
1638 /* Copy the headers to a list and free the array */
1639 new_headers = tny_simple_list_new ();
1640 for (i=0; i < new_headers_array->len; i++) {
1641 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1642 tny_list_append (new_headers, G_OBJECT (header));
1644 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1645 g_ptr_array_free (new_headers_array, FALSE);
1647 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1650 GetMsgInfo *msg_info;
1654 priv->total = tny_list_get_length (new_headers);
1656 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1658 iter = tny_list_create_iterator (new_headers);
1660 /* Create the message info */
1661 msg_info = g_slice_new0 (GetMsgInfo);
1662 msg_info->mail_op = g_object_ref (info->mail_op);
1663 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1664 msg_info->more_msgs = g_object_ref (iter);
1665 msg_info->user_data = info;
1667 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1668 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1669 TnyFolder *folder = tny_header_get_folder (header);
1671 /* Get message in an async way */
1672 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1675 g_object_unref (folder);
1678 tny_iterator_next (iter);
1680 g_object_unref (iter);
1682 /* The mail operation will finish when the last
1683 message is retrieved */
1687 /* If we don't have to retrieve the new messages then
1689 update_account_send_mail (info);
1691 /* Check if the operation was a success */
1693 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1695 /* Call the user callback and free */
1696 update_account_notify_user_and_free (info, new_headers);
1700 inbox_refresh_status_update (GObject *obj,
1704 UpdateAccountInfo *info = NULL;
1705 ModestMailOperation *self = NULL;
1706 ModestMailOperationPrivate *priv = NULL;
1707 ModestMailOperationState *state;
1709 g_return_if_fail (user_data != NULL);
1710 g_return_if_fail (status != NULL);
1712 /* Show only the status information we want */
1713 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1716 info = (UpdateAccountInfo *) user_data;
1717 self = info->mail_op;
1718 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1722 priv->done = status->position;
1723 priv->total = status->of_total;
1725 state = modest_mail_operation_clone_state (self);
1727 /* This is not a GDK lock because we are a Tinymail callback and
1728 * Tinymail already acquires the Gdk lock */
1729 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1731 g_slice_free (ModestMailOperationState, state);
1735 recurse_folders_async_cb (TnyFolderStore *folder_store,
1741 UpdateAccountInfo *info;
1742 ModestMailOperationPrivate *priv;
1744 info = (UpdateAccountInfo *) user_data;
1745 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1747 if (err || canceled) {
1748 /* If the error was previosly set by another callback
1749 don't set it again */
1751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1753 priv->error = g_error_copy (err);
1755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1756 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1760 /* We're not getting INBOX children if we don't want to poke all */
1761 TnyIterator *iter = tny_list_create_iterator (list);
1762 while (!tny_iterator_is_done (iter)) {
1763 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1765 /* Add to the list of all folders */
1766 tny_list_append (info->folders, (GObject *) folder);
1768 if (info->poke_all) {
1769 TnyList *folders = tny_simple_list_new ();
1770 /* Add pending call */
1771 info->pending_calls++;
1773 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1774 recurse_folders_async_cb,
1776 g_object_unref (folders);
1779 g_object_unref (G_OBJECT (folder));
1781 tny_iterator_next (iter);
1783 g_object_unref (G_OBJECT (iter));
1786 /* Remove my own pending call */
1787 info->pending_calls--;
1789 /* This means that we have all the folders */
1790 if (info->pending_calls == 0) {
1791 TnyIterator *iter_all_folders;
1792 TnyFolder *inbox = NULL;
1794 /* If there was any error do not continue */
1796 update_account_notify_user_and_free (info, NULL);
1800 iter_all_folders = tny_list_create_iterator (info->folders);
1802 /* Do a poke status over all folders */
1803 while (!tny_iterator_is_done (iter_all_folders) &&
1804 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1805 TnyFolder *folder = NULL;
1807 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1809 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1810 /* Get a reference to the INBOX */
1811 inbox = g_object_ref (folder);
1813 /* Issue a poke status over the folder */
1815 tny_folder_poke_status (folder);
1818 /* Free and go to next */
1819 g_object_unref (folder);
1820 tny_iterator_next (iter_all_folders);
1822 g_object_unref (iter_all_folders);
1824 /* Refresh the INBOX */
1826 /* Refresh the folder. Our observer receives
1827 * the new emails during folder refreshes, so
1828 * we can use observer->new_headers
1830 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1831 tny_folder_add_observer (inbox, info->inbox_observer);
1833 /* Refresh the INBOX */
1834 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1835 g_object_unref (inbox);
1837 /* We could not perform the inbox refresh but
1838 we'll try to send mails anyway */
1839 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1845 modest_mail_operation_update_account (ModestMailOperation *self,
1846 const gchar *account_name,
1848 gboolean interactive,
1849 RetrieveAllCallback retrieve_all_cb,
1850 UpdateAccountCallback callback,
1853 UpdateAccountInfo *info = NULL;
1854 ModestMailOperationPrivate *priv = NULL;
1855 ModestTnyAccountStore *account_store = NULL;
1857 ModestMailOperationState *state;
1859 /* Init mail operation */
1860 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1863 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1864 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1866 /* Get the store account */
1867 account_store = modest_runtime_get_account_store ();
1869 modest_tny_account_store_get_server_account (account_store,
1871 TNY_ACCOUNT_TYPE_STORE);
1873 /* The above function could return NULL */
1874 if (!priv->account) {
1875 /* Check if the operation was a success */
1876 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1877 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1881 /* Call the user callback */
1883 callback (self, NULL, user_data);
1885 /* Notify about operation end */
1886 modest_mail_operation_notify_end (self);
1891 /* We have once seen priv->account getting finalized during this code,
1892 * therefore adding a reference (bug #82296) */
1894 g_object_ref (priv->account);
1896 /* Create the helper object */
1897 info = g_slice_new0 (UpdateAccountInfo);
1898 info->pending_calls = 1;
1899 info->folders = tny_simple_list_new ();
1900 info->mail_op = g_object_ref (self);
1901 info->poke_all = poke_all;
1902 info->interactive = interactive;
1903 info->account_name = g_strdup (account_name);
1904 info->callback = callback;
1905 info->user_data = user_data;
1906 info->retrieve_all_cb = retrieve_all_cb;
1908 /* Set account busy */
1909 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1910 modest_mail_operation_notify_start (self);
1912 /* notify about the start of the operation */
1913 state = modest_mail_operation_clone_state (self);
1917 /* Start notifying progress */
1918 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1919 g_slice_free (ModestMailOperationState, state);
1921 /* Get all folders and continue in the callback */
1922 folders = tny_simple_list_new ();
1923 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1924 folders, NULL, FALSE,
1925 recurse_folders_async_cb,
1927 g_object_unref (folders);
1929 g_object_unref (priv->account);
1934 * Used to notify the queue from the main
1935 * loop. We call it inside an idle call to achieve that
1938 idle_notify_queue (gpointer data)
1940 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1942 gdk_threads_enter ();
1943 modest_mail_operation_notify_end (mail_op);
1944 gdk_threads_leave ();
1945 g_object_unref (mail_op);
1951 compare_headers_by_date (gconstpointer a,
1954 TnyHeader **header1, **header2;
1955 time_t sent1, sent2;
1957 header1 = (TnyHeader **) a;
1958 header2 = (TnyHeader **) b;
1960 sent1 = tny_header_get_date_sent (*header1);
1961 sent2 = tny_header_get_date_sent (*header2);
1963 /* We want the most recent ones (greater time_t) at the
1972 /* ******************************************************************* */
1973 /* ************************** STORE ACTIONS ************************* */
1974 /* ******************************************************************* */
1977 ModestMailOperation *mail_op;
1978 CreateFolderUserCallback callback;
1984 create_folder_cb (TnyFolderStore *parent_folder,
1986 TnyFolder *new_folder,
1990 ModestMailOperationPrivate *priv;
1991 CreateFolderInfo *info;
1993 info = (CreateFolderInfo *) user_data;
1994 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1996 if (canceled || err) {
1997 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1999 priv->error = g_error_copy (err);
2001 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2002 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2005 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2008 /* The user will unref the new_folder */
2010 info->callback (info->mail_op, parent_folder,
2011 new_folder, info->user_data);
2013 /* Notify about operation end */
2014 modest_mail_operation_notify_end (info->mail_op);
2017 g_object_unref (info->mail_op);
2018 g_slice_free (CreateFolderInfo, info);
2022 modest_mail_operation_create_folder (ModestMailOperation *self,
2023 TnyFolderStore *parent,
2025 CreateFolderUserCallback callback,
2028 ModestMailOperationPrivate *priv;
2030 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2031 g_return_if_fail (name);
2033 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2034 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2035 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2036 g_object_ref (parent) :
2037 modest_tny_folder_get_account (TNY_FOLDER (parent));
2039 /* Check for already existing folder */
2040 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2041 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2042 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2043 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2044 _CS("ckdg_ib_folder_already_exists"));
2048 if (TNY_IS_FOLDER (parent)) {
2049 /* Check folder rules */
2050 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2051 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2052 /* Set status failed and set an error */
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2056 _("mail_in_ui_folder_create_error"));
2060 if (!strcmp (name, " ") || strchr (name, '/')) {
2061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2062 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2063 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2064 _("mail_in_ui_folder_create_error"));
2068 CreateFolderInfo *info;
2070 info = g_slice_new0 (CreateFolderInfo);
2071 info->mail_op = g_object_ref (self);
2072 info->callback = callback;
2073 info->user_data = user_data;
2075 modest_mail_operation_notify_start (self);
2077 /* Create the folder */
2078 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2081 /* Call the user callback anyway */
2083 callback (self, parent, NULL, user_data);
2084 /* Notify about operation end */
2085 modest_mail_operation_notify_end (self);
2090 modest_mail_operation_remove_folder (ModestMailOperation *self,
2092 gboolean remove_to_trash)
2094 ModestMailOperationPrivate *priv;
2095 ModestTnyFolderRules rules;
2097 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2098 g_return_if_fail (TNY_IS_FOLDER (folder));
2100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2102 /* Check folder rules */
2103 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2104 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2105 /* Set status failed and set an error */
2106 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2108 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2109 _("mail_in_ui_folder_delete_error"));
2113 /* Get the account */
2114 priv->account = modest_tny_folder_get_account (folder);
2115 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2117 /* Delete folder or move to trash */
2118 if (remove_to_trash) {
2119 TnyFolder *trash_folder = NULL;
2120 trash_folder = modest_tny_account_get_special_folder (priv->account,
2121 TNY_FOLDER_TYPE_TRASH);
2122 /* TODO: error_handling */
2124 modest_mail_operation_notify_start (self);
2125 modest_mail_operation_xfer_folder (self, folder,
2126 TNY_FOLDER_STORE (trash_folder),
2128 g_object_unref (trash_folder);
2130 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2133 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2135 modest_mail_operation_notify_start (self);
2136 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2137 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2140 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2142 g_object_unref (parent);
2144 g_warning ("%s: could not get parent folder", __FUNCTION__);
2148 /* Notify about operation end */
2149 modest_mail_operation_notify_end (self);
2153 transfer_folder_status_cb (GObject *obj,
2157 ModestMailOperation *self;
2158 ModestMailOperationPrivate *priv;
2159 ModestMailOperationState *state;
2160 XFerFolderAsyncHelper *helper;
2162 g_return_if_fail (status != NULL);
2164 /* Show only the status information we want */
2165 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2168 helper = (XFerFolderAsyncHelper *) user_data;
2169 g_return_if_fail (helper != NULL);
2171 self = helper->mail_op;
2172 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2174 priv->done = status->position;
2175 priv->total = status->of_total;
2177 state = modest_mail_operation_clone_state (self);
2179 /* This is not a GDK lock because we are a Tinymail callback
2180 * which is already GDK locked by Tinymail */
2182 /* no gdk_threads_enter (), CHECKED */
2184 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2186 /* no gdk_threads_leave (), CHECKED */
2188 g_slice_free (ModestMailOperationState, state);
2193 transfer_folder_cb (TnyFolder *folder,
2195 TnyFolderStore *into,
2196 TnyFolder *new_folder,
2200 XFerFolderAsyncHelper *helper;
2201 ModestMailOperation *self = NULL;
2202 ModestMailOperationPrivate *priv = NULL;
2204 helper = (XFerFolderAsyncHelper *) user_data;
2205 g_return_if_fail (helper != NULL);
2207 self = helper->mail_op;
2208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2211 priv->error = g_error_copy (err);
2213 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2214 } else if (cancelled) {
2215 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2216 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2217 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2218 _("Transference of %s was cancelled."),
2219 tny_folder_get_name (folder));
2222 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2225 /* Notify about operation end */
2226 modest_mail_operation_notify_end (self);
2228 /* If user defined callback function was defined, call it */
2229 if (helper->user_callback) {
2231 /* This is not a GDK lock because we are a Tinymail callback
2232 * which is already GDK locked by Tinymail */
2234 /* no gdk_threads_enter (), CHECKED */
2235 helper->user_callback (self, new_folder, helper->user_data);
2236 /* no gdk_threads_leave () , CHECKED */
2240 g_object_unref (helper->mail_op);
2241 g_slice_free (XFerFolderAsyncHelper, helper);
2246 * This function checks if the new name is a valid name for our local
2247 * folders account. The new name could not be the same than then name
2248 * of any of the mandatory local folders
2250 * We can not rely on tinymail because tinymail does not check the
2251 * name of the virtual folders that the account could have in the case
2252 * that we're doing a rename (because it directly calls Camel which
2253 * knows nothing about our virtual folders).
2255 * In the case of an actual copy/move (i.e. move/copy a folder between
2256 * accounts) tinymail uses the tny_folder_store_create_account which
2257 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2258 * checks the new name of the folder, so this call in that case
2259 * wouldn't be needed. *But* NOTE that if tinymail changes its
2260 * implementation (if folder transfers within the same account is no
2261 * longer implemented as a rename) this call will allow Modest to work
2264 * If the new name is not valid, this function will set the status to
2265 * failed and will set also an error in the mail operation
2268 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2269 TnyFolderStore *into,
2270 const gchar *new_name)
2272 if (TNY_IS_ACCOUNT (into) &&
2273 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2274 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2276 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2277 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2278 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2279 _CS("ckdg_ib_folder_already_exists"));
2286 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2288 TnyFolderStore *parent,
2289 gboolean delete_original,
2290 XferFolderAsyncUserCallback user_callback,
2293 ModestMailOperationPrivate *priv = NULL;
2294 ModestTnyFolderRules parent_rules = 0, rules;
2295 XFerFolderAsyncHelper *helper = NULL;
2296 const gchar *folder_name = NULL;
2297 const gchar *error_msg;
2299 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2300 g_return_if_fail (TNY_IS_FOLDER (folder));
2301 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2303 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2304 folder_name = tny_folder_get_name (folder);
2306 /* Set the error msg */
2307 error_msg = _("mail_in_ui_folder_move_target_error");
2309 /* Get account and set it into mail_operation */
2310 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2311 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2312 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2314 /* Get folder rules */
2315 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2316 if (TNY_IS_FOLDER (parent))
2317 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2319 /* Apply operation constraints */
2320 if ((gpointer) parent == (gpointer) folder ||
2321 (!TNY_IS_FOLDER_STORE (parent)) ||
2322 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2325 } else if (TNY_IS_FOLDER (parent) &&
2326 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2330 } else if (TNY_IS_FOLDER (parent) &&
2331 TNY_IS_FOLDER_STORE (folder) &&
2332 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2333 TNY_FOLDER_STORE (folder))) {
2334 /* Do not move a parent into a child */
2336 } else if (TNY_IS_FOLDER_STORE (parent) &&
2337 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2338 /* Check that the new folder name is not used by any
2341 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2342 /* Check that the new folder name is not used by any
2343 special local folder */
2346 /* Create the helper */
2347 helper = g_slice_new0 (XFerFolderAsyncHelper);
2348 helper->mail_op = g_object_ref (self);
2349 helper->user_callback = user_callback;
2350 helper->user_data = user_data;
2352 /* Move/Copy folder */
2353 modest_mail_operation_notify_start (self);
2354 tny_folder_copy_async (folder,
2356 tny_folder_get_name (folder),
2359 transfer_folder_status_cb,
2365 /* Set status failed and set an error */
2366 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2367 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2368 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2371 /* Call the user callback if exists */
2373 user_callback (self, NULL, user_data);
2375 /* Notify the queue */
2376 modest_mail_operation_notify_end (self);
2380 modest_mail_operation_rename_folder (ModestMailOperation *self,
2383 XferFolderAsyncUserCallback user_callback,
2386 ModestMailOperationPrivate *priv;
2387 ModestTnyFolderRules rules;
2388 XFerFolderAsyncHelper *helper;
2390 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2391 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2392 g_return_if_fail (name);
2394 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2396 /* Get account and set it into mail_operation */
2397 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2398 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2400 /* Check folder rules */
2401 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2402 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2404 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2407 TnyFolderStore *into;
2409 into = tny_folder_get_folder_store (folder);
2411 /* Check that the new folder name is not used by any
2412 special local folder */
2413 if (new_name_valid_if_local_account (priv, into, name)) {
2414 /* Create the helper */
2415 helper = g_slice_new0 (XFerFolderAsyncHelper);
2416 helper->mail_op = g_object_ref(self);
2417 helper->user_callback = user_callback;
2418 helper->user_data = user_data;
2420 /* Rename. Camel handles folder subscription/unsubscription */
2421 modest_mail_operation_notify_start (self);
2422 tny_folder_copy_async (folder, into, name, TRUE,
2424 transfer_folder_status_cb,
2426 g_object_unref (into);
2428 g_object_unref (into);
2435 /* Set status failed and set an error */
2436 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2437 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2438 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2439 _("FIXME: unable to rename"));
2442 user_callback (self, NULL, user_data);
2444 /* Notify about operation end */
2445 modest_mail_operation_notify_end (self);
2448 /* ******************************************************************* */
2449 /* ************************** MSG ACTIONS ************************* */
2450 /* ******************************************************************* */
2453 modest_mail_operation_get_msg (ModestMailOperation *self,
2455 gboolean progress_feedback,
2456 GetMsgAsyncUserCallback user_callback,
2459 GetMsgInfo *helper = NULL;
2461 ModestMailOperationPrivate *priv;
2463 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2464 g_return_if_fail (TNY_IS_HEADER (header));
2466 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2467 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2471 /* Check memory low */
2472 if (_check_memory_low (self)) {
2474 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2475 modest_mail_operation_notify_end (self);
2479 /* Get account and set it into mail_operation */
2480 folder = tny_header_get_folder (header);
2481 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2483 /* Check for cached messages */
2484 if (progress_feedback) {
2485 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2486 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2488 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2490 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2493 /* Create the helper */
2494 helper = g_slice_new0 (GetMsgInfo);
2495 helper->header = g_object_ref (header);
2496 helper->mail_op = g_object_ref (self);
2497 helper->user_callback = user_callback;
2498 helper->user_data = user_data;
2499 helper->destroy_notify = NULL;
2500 helper->last_total_bytes = 0;
2501 helper->sum_total_bytes = 0;
2502 helper->total_bytes = tny_header_get_message_size (header);
2503 helper->more_msgs = NULL;
2505 modest_mail_operation_notify_start (self);
2507 /* notify about the start of the operation */
2508 ModestMailOperationState *state;
2509 state = modest_mail_operation_clone_state (self);
2512 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2514 g_slice_free (ModestMailOperationState, state);
2516 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2518 g_object_unref (G_OBJECT (folder));
2522 get_msg_status_cb (GObject *obj,
2526 GetMsgInfo *helper = NULL;
2528 g_return_if_fail (status != NULL);
2530 /* Show only the status information we want */
2531 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2534 helper = (GetMsgInfo *) user_data;
2535 g_return_if_fail (helper != NULL);
2537 /* Notify progress */
2538 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2539 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2543 get_msg_async_cb (TnyFolder *folder,
2549 GetMsgInfo *info = NULL;
2550 ModestMailOperationPrivate *priv = NULL;
2553 info = (GetMsgInfo *) user_data;
2555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2558 if (info->more_msgs) {
2559 tny_iterator_next (info->more_msgs);
2560 finished = (tny_iterator_is_done (info->more_msgs));
2562 finished = (priv->done == priv->total) ? TRUE : FALSE;
2565 /* If canceled by the user, ignore the error given by Tinymail */
2569 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2571 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2573 priv->error = g_error_copy ((const GError *) err);
2574 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2577 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2578 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2581 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2582 /* Set the success status before calling the user callback */
2583 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2587 /* Call the user callback */
2588 if (info->user_callback)
2589 info->user_callback (info->mail_op, info->header, canceled,
2590 msg, err, info->user_data);
2592 /* Notify about operation end if this is the last callback */
2594 /* Free user data */
2595 if (info->destroy_notify)
2596 info->destroy_notify (info->user_data);
2598 /* Notify about operation end */
2599 modest_mail_operation_notify_end (info->mail_op);
2602 if (info->more_msgs)
2603 g_object_unref (info->more_msgs);
2604 g_object_unref (info->header);
2605 g_object_unref (info->mail_op);
2606 g_slice_free (GetMsgInfo, info);
2607 } else if (info->more_msgs) {
2608 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2609 TnyFolder *folder = tny_header_get_folder (header);
2611 g_object_unref (info->header);
2612 info->header = g_object_ref (header);
2614 /* Retrieve the next message */
2615 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2617 g_object_unref (header);
2618 g_object_unref (folder);
2620 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2625 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2626 TnyList *header_list,
2627 GetMsgAsyncUserCallback user_callback,
2629 GDestroyNotify notify)
2631 ModestMailOperationPrivate *priv = NULL;
2633 TnyIterator *iter = NULL;
2634 gboolean has_uncached_messages;
2636 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2638 /* Init mail operation */
2639 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2640 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2642 priv->total = tny_list_get_length(header_list);
2644 /* Check memory low */
2645 if (_check_memory_low (self)) {
2646 if (user_callback) {
2647 TnyHeader *header = NULL;
2650 if (tny_list_get_length (header_list) > 0) {
2651 iter = tny_list_create_iterator (header_list);
2652 header = (TnyHeader *) tny_iterator_get_current (iter);
2653 g_object_unref (iter);
2655 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2657 g_object_unref (header);
2661 /* Notify about operation end */
2662 modest_mail_operation_notify_end (self);
2666 /* Check uncached messages */
2667 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2668 !has_uncached_messages && !tny_iterator_is_done (iter);
2669 tny_iterator_next (iter)) {
2672 header = (TnyHeader *) tny_iterator_get_current (iter);
2673 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2674 has_uncached_messages = TRUE;
2675 g_object_unref (header);
2677 g_object_unref (iter);
2678 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2680 /* Get account and set it into mail_operation */
2681 if (tny_list_get_length (header_list) >= 1) {
2682 TnyIterator *iterator = tny_list_create_iterator (header_list);
2683 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2685 TnyFolder *folder = tny_header_get_folder (header);
2687 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2688 g_object_unref (folder);
2690 g_object_unref (header);
2692 g_object_unref (iterator);
2695 msg_list_size = compute_message_list_size (header_list, 0);
2697 modest_mail_operation_notify_start (self);
2698 iter = tny_list_create_iterator (header_list);
2699 if (!tny_iterator_is_done (iter)) {
2700 /* notify about the start of the operation */
2701 ModestMailOperationState *state;
2702 state = modest_mail_operation_clone_state (self);
2705 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2708 GetMsgInfo *msg_info = NULL;
2709 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2710 TnyFolder *folder = tny_header_get_folder (header);
2712 /* Create the message info */
2713 msg_info = g_slice_new0 (GetMsgInfo);
2714 msg_info->mail_op = g_object_ref (self);
2715 msg_info->header = g_object_ref (header);
2716 msg_info->more_msgs = g_object_ref (iter);
2717 msg_info->user_callback = user_callback;
2718 msg_info->user_data = user_data;
2719 msg_info->destroy_notify = notify;
2720 msg_info->last_total_bytes = 0;
2721 msg_info->sum_total_bytes = 0;
2722 msg_info->total_bytes = msg_list_size;
2724 /* The callback will call it per each header */
2725 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2727 /* Free and go on */
2728 g_object_unref (header);
2729 g_object_unref (folder);
2730 g_slice_free (ModestMailOperationState, state);
2732 g_object_unref (iter);
2737 remove_msgs_async_cb (TnyFolder *folder,
2742 gboolean expunge, leave_on_server;
2743 const gchar *account_name;
2744 TnyAccount *account;
2745 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2746 ModestMailOperation *self;
2747 ModestMailOperationPrivate *priv;
2748 ModestProtocolRegistry *protocol_registry;
2750 self = (ModestMailOperation *) user_data;
2751 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2752 protocol_registry = modest_runtime_get_protocol_registry ();
2754 if (canceled || err) {
2755 /* If canceled by the user, ignore the error given by Tinymail */
2757 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2759 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2760 priv->error = g_error_copy ((const GError *) err);
2761 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2764 modest_mail_operation_notify_end (self);
2765 g_object_unref (self);
2769 account = tny_folder_get_account (folder);
2770 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2772 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2774 account_proto = modest_tny_account_get_protocol_type (account);
2775 g_object_unref (account);
2777 if (( (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) && !leave_on_server) ||
2778 modest_tny_folder_is_remote_folder (folder) == FALSE))
2784 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2789 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2791 gboolean remove_to_trash /*ignored*/)
2793 TnyFolder *folder = NULL;
2794 ModestMailOperationPrivate *priv;
2795 TnyIterator *iter = NULL;
2796 TnyHeader *header = NULL;
2797 TnyList *remove_headers = NULL;
2798 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2800 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2801 g_return_if_fail (TNY_IS_LIST (headers));
2803 if (remove_to_trash)
2804 g_warning ("remove to trash is not implemented");
2806 if (tny_list_get_length(headers) == 0) {
2807 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2808 goto cleanup; /* nothing to do */
2811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2812 remove_headers = g_object_ref(headers);
2814 /* Get folder from first header and sync it */
2815 iter = tny_list_create_iterator (headers);
2816 header = TNY_HEADER (tny_iterator_get_current (iter));
2818 folder = tny_header_get_folder (header);
2819 if (!TNY_IS_FOLDER(folder)) {
2820 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2824 /* Don't remove messages that are being sent */
2825 if (modest_tny_folder_is_local_folder (folder)) {
2826 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2828 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2829 TnyTransportAccount *traccount = NULL;
2830 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2831 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2833 ModestTnySendQueueStatus status;
2834 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2836 if (TNY_IS_SEND_QUEUE (send_queue)) {
2837 TnyIterator *iter = tny_list_create_iterator(headers);
2838 g_object_unref(remove_headers);
2839 remove_headers = TNY_LIST(tny_simple_list_new());
2840 while (!tny_iterator_is_done(iter)) {
2842 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2843 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2844 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2845 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2846 tny_list_append(remove_headers, G_OBJECT(hdr));
2848 g_object_unref(hdr);
2850 tny_iterator_next(iter);
2852 g_object_unref(iter);
2854 g_object_unref(traccount);
2858 /* Get account and set it into mail_operation */
2859 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2860 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2861 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2863 /* remove message from folder */
2864 modest_mail_operation_notify_start (self);
2865 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2866 NULL, g_object_ref (self));
2870 g_object_unref (remove_headers);
2872 g_object_unref (header);
2874 g_object_unref (iter);
2876 g_object_unref (folder);
2880 notify_progress_of_multiple_messages (ModestMailOperation *self,
2882 gint *last_total_bytes,
2883 gint *sum_total_bytes,
2885 gboolean increment_done)
2887 ModestMailOperationPrivate *priv;
2888 ModestMailOperationState *state;
2889 gboolean is_num_bytes = FALSE;
2891 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2893 /* We know that tinymail sends us information about
2894 * transferred bytes with this particular message
2896 if (status->message)
2897 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2899 state = modest_mail_operation_clone_state (self);
2900 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2901 /* We know that we're in a different message when the
2902 total number of bytes to transfer is different. Of
2903 course it could fail if we're transferring messages
2904 of the same size, but this is a workarround */
2905 if (status->of_total != *last_total_bytes) {
2906 /* We need to increment the done when there is
2907 no information about each individual
2908 message, we need to do this in message
2909 transfers, and we don't do it for getting
2913 *sum_total_bytes += *last_total_bytes;
2914 *last_total_bytes = status->of_total;
2916 state->bytes_done += status->position + *sum_total_bytes;
2917 state->bytes_total = total_bytes;
2919 /* Notify the status change. Only notify about changes
2920 referred to bytes */
2921 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2925 g_slice_free (ModestMailOperationState, state);
2929 transfer_msgs_status_cb (GObject *obj,
2933 XFerMsgsAsyncHelper *helper;
2935 g_return_if_fail (status != NULL);
2937 /* Show only the status information we want */
2938 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2941 helper = (XFerMsgsAsyncHelper *) user_data;
2942 g_return_if_fail (helper != NULL);
2944 /* Notify progress */
2945 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2946 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2950 transfer_msgs_sync_folder_cb (TnyFolder *self,
2955 XFerMsgsAsyncHelper *helper;
2956 /* We don't care here about the results of the
2958 helper = (XFerMsgsAsyncHelper *) user_data;
2960 /* Notify about operation end */
2961 modest_mail_operation_notify_end (helper->mail_op);
2963 /* If user defined callback function was defined, call it */
2964 if (helper->user_callback)
2965 helper->user_callback (helper->mail_op, helper->user_data);
2968 if (helper->more_msgs)
2969 g_object_unref (helper->more_msgs);
2970 if (helper->headers)
2971 g_object_unref (helper->headers);
2972 if (helper->dest_folder)
2973 g_object_unref (helper->dest_folder);
2974 if (helper->mail_op)
2975 g_object_unref (helper->mail_op);
2976 g_slice_free (XFerMsgsAsyncHelper, helper);
2980 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2982 XFerMsgsAsyncHelper *helper;
2983 ModestMailOperation *self;
2984 ModestMailOperationPrivate *priv;
2985 gboolean finished = TRUE;
2987 helper = (XFerMsgsAsyncHelper *) user_data;
2988 self = helper->mail_op;
2990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2993 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2995 priv->error = g_error_copy (err);
2997 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2998 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2999 if (helper->more_msgs) {
3000 /* We'll transfer the next message in the list */
3001 tny_iterator_next (helper->more_msgs);
3002 if (!tny_iterator_is_done (helper->more_msgs)) {
3003 GObject *next_header;
3004 g_object_unref (helper->headers);
3005 helper->headers = tny_simple_list_new ();
3006 next_header = tny_iterator_get_current (helper->more_msgs);
3007 tny_list_append (helper->headers, next_header);
3008 g_object_unref (next_header);
3014 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3019 /* Synchronize the source folder contents. This should
3020 be done by tinymail but the camel_folder_sync it's
3021 actually disabled in transfer_msgs_thread_clean
3022 because it's supposed to cause hangs */
3023 tny_folder_sync_async (folder, helper->delete,
3024 transfer_msgs_sync_folder_cb,
3027 /* Transfer more messages */
3028 tny_folder_transfer_msgs_async (folder,
3030 helper->dest_folder,
3033 transfer_msgs_status_cb,
3038 /* Computes the size of the messages the headers in the list belongs
3039 to. If num_elements is different from 0 then it only takes into
3040 account the first num_elements for the calculation */
3042 compute_message_list_size (TnyList *headers,
3046 guint size = 0, element = 0;
3048 /* If num_elements is not valid then take all into account */
3049 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3050 num_elements = tny_list_get_length (headers);
3052 iter = tny_list_create_iterator (headers);
3053 while (!tny_iterator_is_done (iter) && element < num_elements) {
3054 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3055 size += tny_header_get_message_size (header);
3056 g_object_unref (header);
3057 tny_iterator_next (iter);
3060 g_object_unref (iter);
3066 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3069 gboolean delete_original,
3070 XferMsgsAsyncUserCallback user_callback,
3073 ModestMailOperationPrivate *priv = NULL;
3074 TnyIterator *iter = NULL;
3075 TnyFolder *src_folder = NULL;
3076 XFerMsgsAsyncHelper *helper = NULL;
3077 TnyHeader *header = NULL;
3078 ModestTnyFolderRules rules = 0;
3079 TnyAccount *dst_account = NULL;
3080 gboolean leave_on_server;
3081 ModestMailOperationState *state;
3082 ModestProtocolRegistry *protocol_registry;
3083 ModestProtocolType account_protocol;
3085 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3086 g_return_if_fail (headers && TNY_IS_LIST (headers));
3087 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3089 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3090 protocol_registry = modest_runtime_get_protocol_registry ();
3092 priv->total = tny_list_get_length (headers);
3094 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3095 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3097 /* Apply folder rules */
3098 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3099 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3100 /* Set status failed and set an error */
3101 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3102 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3103 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3104 _CS("ckct_ib_unable_to_paste_here"));
3105 /* Notify the queue */
3106 modest_mail_operation_notify_end (self);
3110 /* Get source folder */
3111 iter = tny_list_create_iterator (headers);
3112 header = TNY_HEADER (tny_iterator_get_current (iter));
3114 src_folder = tny_header_get_folder (header);
3115 g_object_unref (header);
3117 g_object_unref (iter);
3119 if (src_folder == NULL) {
3120 /* Notify the queue */
3121 modest_mail_operation_notify_end (self);
3123 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3128 /* Check folder source and destination */
3129 if (src_folder == folder) {
3130 /* Set status failed and set an error */
3131 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3132 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3133 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3134 _("mail_in_ui_folder_copy_target_error"));
3136 /* Notify the queue */
3137 modest_mail_operation_notify_end (self);
3140 g_object_unref (src_folder);
3144 /* Create the helper */
3145 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3146 helper->mail_op = g_object_ref(self);
3147 helper->dest_folder = g_object_ref(folder);
3148 helper->user_callback = user_callback;
3149 helper->user_data = user_data;
3150 helper->last_total_bytes = 0;
3151 helper->sum_total_bytes = 0;
3152 helper->total_bytes = compute_message_list_size (headers, 0);
3154 /* Get account and set it into mail_operation */
3155 priv->account = modest_tny_folder_get_account (src_folder);
3156 dst_account = modest_tny_folder_get_account (folder);
3158 if (priv->account == dst_account) {
3159 /* Transfer all messages at once using the fast
3160 * method. Note that depending on the server this
3161 * might not be that fast, and might not be
3162 * user-cancellable either */
3163 helper->headers = g_object_ref (headers);
3164 helper->more_msgs = NULL;
3166 /* Transfer messages one by one so the user can cancel
3169 helper->headers = tny_simple_list_new ();
3170 helper->more_msgs = tny_list_create_iterator (headers);
3171 hdr = tny_iterator_get_current (helper->more_msgs);
3172 tny_list_append (helper->headers, hdr);
3173 g_object_unref (hdr);
3176 /* If leave_on_server is set to TRUE then don't use
3177 delete_original, we always pass FALSE. This is because
3178 otherwise tinymail will try to sync the source folder and
3179 this could cause an error if we're offline while
3180 transferring an already downloaded message from a POP
3182 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3183 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3184 const gchar *account_name;
3186 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3187 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3190 leave_on_server = FALSE;
3193 /* Do not delete messages if leave on server is TRUE */
3194 helper->delete = (leave_on_server) ? FALSE : delete_original;
3196 modest_mail_operation_notify_start (self);
3198 /* Start notifying progress */
3199 state = modest_mail_operation_clone_state (self);
3202 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3203 g_slice_free (ModestMailOperationState, state);
3205 tny_folder_transfer_msgs_async (src_folder,
3210 transfer_msgs_status_cb,
3212 g_object_unref (src_folder);
3213 g_object_unref (dst_account);
3218 on_refresh_folder (TnyFolder *folder,
3223 RefreshAsyncHelper *helper = NULL;
3224 ModestMailOperation *self = NULL;
3225 ModestMailOperationPrivate *priv = NULL;
3227 helper = (RefreshAsyncHelper *) user_data;
3228 self = helper->mail_op;
3229 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3231 g_return_if_fail(priv!=NULL);
3234 priv->error = g_error_copy (error);
3235 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3240 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3241 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3242 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3243 _("Error trying to refresh the contents of %s"),
3244 tny_folder_get_name (folder));
3248 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3251 /* Call user defined callback, if it exists */
3252 if (helper->user_callback) {
3254 /* This is not a GDK lock because we are a Tinymail callback and
3255 * Tinymail already acquires the Gdk lock */
3256 helper->user_callback (self, folder, helper->user_data);
3260 g_slice_free (RefreshAsyncHelper, helper);
3262 /* Notify about operation end */
3263 modest_mail_operation_notify_end (self);
3264 g_object_unref(self);
3268 on_refresh_folder_status_update (GObject *obj,
3272 RefreshAsyncHelper *helper = NULL;
3273 ModestMailOperation *self = NULL;
3274 ModestMailOperationPrivate *priv = NULL;
3275 ModestMailOperationState *state;
3277 g_return_if_fail (user_data != NULL);
3278 g_return_if_fail (status != NULL);
3280 /* Show only the status information we want */
3281 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3284 helper = (RefreshAsyncHelper *) user_data;
3285 self = helper->mail_op;
3286 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3288 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3290 priv->done = status->position;
3291 priv->total = status->of_total;
3293 state = modest_mail_operation_clone_state (self);
3295 /* This is not a GDK lock because we are a Tinymail callback and
3296 * Tinymail already acquires the Gdk lock */
3297 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3299 g_slice_free (ModestMailOperationState, state);
3303 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3305 RefreshAsyncUserCallback user_callback,
3308 ModestMailOperationPrivate *priv = NULL;
3309 RefreshAsyncHelper *helper = NULL;
3311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3313 /* Check memory low */
3314 if (_check_memory_low (self)) {
3316 user_callback (self, folder, user_data);
3317 /* Notify about operation end */
3318 modest_mail_operation_notify_end (self);
3322 /* Get account and set it into mail_operation */
3323 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3324 priv->account = modest_tny_folder_get_account (folder);
3325 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3327 /* Create the helper */
3328 helper = g_slice_new0 (RefreshAsyncHelper);
3329 helper->mail_op = g_object_ref(self);
3330 helper->user_callback = user_callback;
3331 helper->user_data = user_data;
3333 modest_mail_operation_notify_start (self);
3335 /* notify that the operation was started */
3336 ModestMailOperationState *state;
3337 state = modest_mail_operation_clone_state (self);
3340 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3342 g_slice_free (ModestMailOperationState, state);
3344 tny_folder_refresh_async (folder,
3346 on_refresh_folder_status_update,
3351 run_queue_notify_and_destroy (RunQueueHelper *helper,
3352 ModestMailOperationStatus status)
3354 ModestMailOperationPrivate *priv;
3357 if (helper->error_handler &&
3358 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3359 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3360 if (helper->start_handler &&
3361 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3362 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3363 if (helper->stop_handler &&
3364 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3365 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3368 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3369 priv->status = status;
3372 modest_mail_operation_notify_end (helper->self);
3375 g_object_unref (helper->queue);
3376 g_object_unref (helper->self);
3377 g_slice_free (RunQueueHelper, helper);
3381 run_queue_stop (ModestTnySendQueue *queue,
3384 RunQueueHelper *helper;
3386 g_debug ("%s sending queue stopped", __FUNCTION__);
3388 helper = (RunQueueHelper *) user_data;
3389 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3393 modest_mail_operation_run_queue (ModestMailOperation *self,
3394 ModestTnySendQueue *queue)
3396 ModestMailOperationPrivate *priv;
3397 RunQueueHelper *helper;
3399 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3400 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3403 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3404 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3405 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3407 /* Create the helper */
3408 helper = g_slice_new0 (RunQueueHelper);
3409 helper->queue = g_object_ref (queue);
3410 helper->self = g_object_ref (self);
3411 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3412 G_CALLBACK (run_queue_stop),
3415 /* Notify operation has started */
3416 modest_mail_operation_notify_start (self);
3417 g_debug ("%s, run queue started", __FUNCTION__);
3421 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3423 ModestMailOperation *self = (ModestMailOperation *) userdata;
3424 ModestMailOperationPrivate *priv;
3426 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3427 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3428 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3430 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3432 modest_mail_operation_notify_end (self);
3433 g_object_unref (self);
3437 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3439 ModestMailOperationPrivate *priv;
3441 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3442 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3445 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3447 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3448 priv->account = NULL;
3449 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3451 modest_mail_operation_notify_start (self);
3452 g_object_ref (self);
3453 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3457 sync_folder_finish_callback (TnyFolder *self,
3463 ModestMailOperation *mail_op;
3464 ModestMailOperationPrivate *priv;
3466 mail_op = (ModestMailOperation *) user_data;
3467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3469 /* If canceled by the user, ignore the error given by Tinymail */
3471 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3473 /* If the operation was a sync then the status is
3474 failed, but if it's part of another operation then
3475 just set it as finished with errors */
3476 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3477 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3479 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3480 priv->error = g_error_copy ((const GError *) err);
3481 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3483 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3486 modest_mail_operation_notify_end (mail_op);
3487 g_object_unref (mail_op);
3491 modest_mail_operation_sync_folder (ModestMailOperation *self,
3492 TnyFolder *folder, gboolean expunge)
3494 ModestMailOperationPrivate *priv;
3496 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3497 g_return_if_fail (TNY_IS_FOLDER (folder));
3498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3500 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3501 priv->account = modest_tny_folder_get_account (folder);
3502 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3504 modest_mail_operation_notify_start (self);
3505 g_object_ref (self);
3506 tny_folder_sync_async (folder, expunge,
3507 (TnyFolderCallback) sync_folder_finish_callback,
3512 modest_mail_operation_notify_start (ModestMailOperation *self)
3514 ModestMailOperationPrivate *priv = NULL;
3516 g_return_if_fail (self);
3518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3520 /* Ensure that all the fields are filled correctly */
3521 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3523 /* Notify the observers about the mail operation. We do not
3524 wrapp this emission because we assume that this function is
3525 always called from within the main lock */
3526 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3531 * It's used by the mail operation queue to notify the observers
3532 * attached to that signal that the operation finished. We need to use
3533 * that because tinymail does not give us the progress of a given
3534 * operation when it finishes (it directly calls the operation
3538 modest_mail_operation_notify_end (ModestMailOperation *self)
3540 ModestMailOperationPrivate *priv = NULL;
3542 g_return_if_fail (self);
3544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3546 /* Notify the observers about the mail operation end. We do
3547 not wrapp this emission because we assume that this
3548 function is always called from within the main lock */
3549 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3551 /* Remove the error user data */
3552 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3553 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3557 modest_mail_operation_get_account (ModestMailOperation *self)
3559 ModestMailOperationPrivate *priv = NULL;
3561 g_return_val_if_fail (self, NULL);
3563 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3565 return (priv->account) ? g_object_ref (priv->account) : NULL;
3569 modest_mail_operation_noop (ModestMailOperation *self)
3571 ModestMailOperationPrivate *priv = NULL;
3573 g_return_if_fail (self);
3575 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3576 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3577 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3581 /* This mail operation does nothing actually */
3582 modest_mail_operation_notify_start (self);
3583 modest_mail_operation_notify_end (self);
3588 modest_mail_operation_to_string (ModestMailOperation *self)
3590 const gchar *type, *status, *account_id;
3591 ModestMailOperationPrivate *priv = NULL;
3593 g_return_val_if_fail (self, NULL);
3595 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3597 /* new operations don't have anything interesting */
3598 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3599 return g_strdup_printf ("%p <new operation>", self);
3601 switch (priv->op_type) {
3602 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3603 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3604 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3605 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3606 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3607 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3608 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3609 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3610 default: type = "UNEXPECTED"; break;
3613 switch (priv->status) {
3614 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3615 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3616 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3617 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3618 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3619 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3620 default: status= "UNEXPECTED"; break;
3623 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3625 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3626 priv->done, priv->total,
3627 priv->error && priv->error->message ? priv->error->message : "");
3631 * Once the mail operations were objects this will be no longer
3632 * needed. I don't like it, but we need it for the moment
3635 _check_memory_low (ModestMailOperation *mail_op)
3637 if (modest_platform_check_memory_low (NULL, FALSE)) {
3638 ModestMailOperationPrivate *priv;
3640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3641 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3642 g_set_error (&(priv->error),
3643 MODEST_MAIL_OPERATION_ERROR,
3644 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3645 "Not enough memory to complete the operation");