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_append (TNY_LIST (user_data), G_OBJECT (header));
1335 /* This is the method that looks for new messages in a folder */
1337 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1339 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1341 TnyFolderChangeChanged changed;
1343 changed = tny_folder_change_get_changed (change);
1345 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1348 /* Get added headers */
1349 list = tny_simple_list_new ();
1350 tny_folder_change_get_added_headers (change, list);
1352 /* Add them to the folder observer */
1353 tny_list_foreach (list, foreach_add_item,
1354 derived->new_headers);
1356 g_object_unref (G_OBJECT (list));
1361 internal_folder_observer_init (InternalFolderObserver *self)
1363 self->new_headers = tny_simple_list_new ();
1366 internal_folder_observer_finalize (GObject *object)
1368 InternalFolderObserver *self;
1370 self = (InternalFolderObserver *) object;
1371 g_object_unref (self->new_headers);
1373 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1376 tny_folder_observer_init (TnyFolderObserverIface *iface)
1378 iface->update = internal_folder_observer_update;
1381 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1383 GObjectClass *object_class;
1385 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1386 object_class = (GObjectClass*) klass;
1387 object_class->finalize = internal_folder_observer_finalize;
1391 destroy_update_account_info (UpdateAccountInfo *info)
1393 g_free (info->account_name);
1394 g_object_unref (info->folders);
1395 g_object_unref (info->mail_op);
1396 g_slice_free (UpdateAccountInfo, info);
1401 update_account_send_mail (UpdateAccountInfo *info)
1403 TnyTransportAccount *transport_account = NULL;
1404 ModestTnyAccountStore *account_store;
1406 account_store = modest_runtime_get_account_store ();
1408 /* We don't try to send messages while sending mails is blocked */
1409 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1412 /* Get the transport account */
1413 transport_account = (TnyTransportAccount *)
1414 modest_tny_account_store_get_server_account (account_store, info->account_name,
1415 TNY_ACCOUNT_TYPE_TRANSPORT);
1417 if (transport_account) {
1418 ModestTnySendQueue *send_queue;
1422 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1423 g_object_unref (transport_account);
1425 if (TNY_IS_SEND_QUEUE (send_queue)) {
1426 /* Get outbox folder */
1427 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1428 if (outbox) { /* this could fail in some cases */
1429 num_messages = tny_folder_get_all_count (outbox);
1430 g_object_unref (outbox);
1432 g_warning ("%s: could not get outbox", __FUNCTION__);
1436 if (num_messages != 0) {
1437 /* Reenable suspended items */
1438 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1441 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1442 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1450 update_account_get_msg_async_cb (TnyFolder *folder,
1456 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1457 ModestMailOperationPrivate *priv;
1459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1462 if (TNY_IS_MSG (msg)) {
1463 TnyHeader *header = tny_msg_get_header (msg);
1466 ModestMailOperationState *state;
1467 state = modest_mail_operation_clone_state (msg_info->mail_op);
1468 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1469 state->bytes_done = msg_info->sum_total_bytes;
1470 state->bytes_total = msg_info->total_bytes;
1472 /* Notify the status change. Only notify about changes
1473 referred to bytes */
1474 g_signal_emit (G_OBJECT (msg_info->mail_op),
1475 signals[PROGRESS_CHANGED_SIGNAL],
1478 g_object_unref (header);
1479 g_slice_free (ModestMailOperationState, state);
1483 if (priv->done == priv->total) {
1484 TnyList *new_headers;
1485 UpdateAccountInfo *info;
1487 /* After getting all the messages send the ones in the
1489 info = (UpdateAccountInfo *) msg_info->user_data;
1490 update_account_send_mail (info);
1492 /* Check if the operation was a success */
1494 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1496 /* Call the user callback and free */
1497 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1498 update_account_notify_user_and_free (info, new_headers);
1499 g_object_unref (new_headers);
1501 /* Delete the helper */
1502 g_object_unref (msg_info->more_msgs);
1503 g_object_unref (msg_info->mail_op);
1504 g_slice_free (GetMsgInfo, msg_info);
1509 update_account_notify_user_and_free (UpdateAccountInfo *info,
1510 TnyList *new_headers)
1512 /* Set the account back to not busy */
1513 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1514 info->account_name, FALSE);
1518 info->callback (info->mail_op, new_headers, info->user_data);
1520 /* Mail operation end */
1521 modest_mail_operation_notify_end (info->mail_op);
1525 g_object_unref (new_headers);
1526 destroy_update_account_info (info);
1530 inbox_refreshed_cb (TnyFolder *inbox,
1535 UpdateAccountInfo *info;
1536 ModestMailOperationPrivate *priv;
1537 TnyIterator *new_headers_iter;
1538 GPtrArray *new_headers_array = NULL;
1539 gint max_size, retrieve_limit, i;
1540 ModestAccountMgr *mgr;
1541 ModestAccountRetrieveType retrieve_type;
1542 TnyList *new_headers = NULL;
1543 gboolean headers_only, ignore_limit;
1545 info = (UpdateAccountInfo *) user_data;
1546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1547 mgr = modest_runtime_get_account_mgr ();
1549 if (canceled || err) {
1550 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1552 priv->error = g_error_copy (err);
1554 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1555 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1558 tny_folder_remove_observer (inbox, info->inbox_observer);
1559 g_object_unref (info->inbox_observer);
1560 info->inbox_observer = NULL;
1562 /* Notify the user about the error and then exit */
1563 update_account_notify_user_and_free (info, NULL);
1568 /* Try to send anyway */
1572 /* Set the last updated as the current time */
1573 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1575 /* Get the message max size */
1576 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1577 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1579 max_size = G_MAXINT;
1581 max_size = max_size * KB;
1583 /* Create the new headers array. We need it to sort the
1584 new headers by date */
1585 new_headers_array = g_ptr_array_new ();
1586 if (info->inbox_observer) {
1587 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1588 while (!tny_iterator_is_done (new_headers_iter)) {
1589 TnyHeader *header = NULL;
1591 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1592 /* Apply per-message size limits */
1593 if (tny_header_get_message_size (header) < max_size)
1594 g_ptr_array_add (new_headers_array, g_object_ref (header));
1596 g_object_unref (header);
1597 tny_iterator_next (new_headers_iter);
1599 g_object_unref (new_headers_iter);
1601 tny_folder_remove_observer (inbox, info->inbox_observer);
1602 g_object_unref (info->inbox_observer);
1603 info->inbox_observer = NULL;
1606 if (new_headers_array->len == 0) {
1607 g_ptr_array_free (new_headers_array, FALSE);
1611 /* Get per-account message amount retrieval limit */
1612 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1613 if (retrieve_limit == 0)
1614 retrieve_limit = G_MAXINT;
1616 /* Get per-account retrieval type */
1617 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1618 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1621 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1623 /* Ask the users if they want to retrieve all the messages
1624 even though the limit was exceeded */
1625 ignore_limit = FALSE;
1626 if (new_headers_array->len > retrieve_limit) {
1627 /* Ask the user if a callback has been specified and
1628 if the mail operation has a source (this means that
1629 was invoked by the user and not automatically by a
1631 if (info->retrieve_all_cb && priv->source)
1632 ignore_limit = info->retrieve_all_cb (priv->source,
1633 new_headers_array->len,
1637 /* Copy the headers to a list and free the array */
1638 new_headers = tny_simple_list_new ();
1639 for (i=0; i < new_headers_array->len; i++) {
1640 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1641 tny_list_append (new_headers, G_OBJECT (header));
1643 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1644 g_ptr_array_free (new_headers_array, FALSE);
1646 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1649 GetMsgInfo *msg_info;
1653 priv->total = tny_list_get_length (new_headers);
1655 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1657 iter = tny_list_create_iterator (new_headers);
1659 /* Create the message info */
1660 msg_info = g_slice_new0 (GetMsgInfo);
1661 msg_info->mail_op = g_object_ref (info->mail_op);
1662 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1663 msg_info->more_msgs = g_object_ref (iter);
1664 msg_info->user_data = info;
1666 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1667 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1668 TnyFolder *folder = tny_header_get_folder (header);
1670 /* Get message in an async way */
1671 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1674 g_object_unref (folder);
1677 tny_iterator_next (iter);
1679 g_object_unref (iter);
1681 /* The mail operation will finish when the last
1682 message is retrieved */
1686 /* If we don't have to retrieve the new messages then
1688 update_account_send_mail (info);
1690 /* Check if the operation was a success */
1692 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1694 /* Call the user callback and free */
1695 update_account_notify_user_and_free (info, new_headers);
1699 inbox_refresh_status_update (GObject *obj,
1703 UpdateAccountInfo *info = NULL;
1704 ModestMailOperation *self = NULL;
1705 ModestMailOperationPrivate *priv = NULL;
1706 ModestMailOperationState *state;
1708 g_return_if_fail (user_data != NULL);
1709 g_return_if_fail (status != NULL);
1711 /* Show only the status information we want */
1712 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1715 info = (UpdateAccountInfo *) user_data;
1716 self = info->mail_op;
1717 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1719 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1721 priv->done = status->position;
1722 priv->total = status->of_total;
1724 state = modest_mail_operation_clone_state (self);
1726 /* This is not a GDK lock because we are a Tinymail callback and
1727 * Tinymail already acquires the Gdk lock */
1728 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1730 g_slice_free (ModestMailOperationState, state);
1734 recurse_folders_async_cb (TnyFolderStore *folder_store,
1740 UpdateAccountInfo *info;
1741 ModestMailOperationPrivate *priv;
1743 info = (UpdateAccountInfo *) user_data;
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1746 if (err || canceled) {
1747 /* If the error was previosly set by another callback
1748 don't set it again */
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1752 priv->error = g_error_copy (err);
1754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1755 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1759 /* We're not getting INBOX children if we don't want to poke all */
1760 TnyIterator *iter = tny_list_create_iterator (list);
1761 while (!tny_iterator_is_done (iter)) {
1762 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1764 /* Add to the list of all folders */
1765 tny_list_append (info->folders, (GObject *) folder);
1767 if (info->poke_all) {
1768 TnyList *folders = tny_simple_list_new ();
1769 /* Add pending call */
1770 info->pending_calls++;
1772 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1773 recurse_folders_async_cb,
1775 g_object_unref (folders);
1778 g_object_unref (G_OBJECT (folder));
1780 tny_iterator_next (iter);
1782 g_object_unref (G_OBJECT (iter));
1785 /* Remove my own pending call */
1786 info->pending_calls--;
1788 /* This means that we have all the folders */
1789 if (info->pending_calls == 0) {
1790 TnyIterator *iter_all_folders;
1791 TnyFolder *inbox = NULL;
1793 /* If there was any error do not continue */
1795 update_account_notify_user_and_free (info, NULL);
1799 iter_all_folders = tny_list_create_iterator (info->folders);
1801 /* Do a poke status over all folders */
1802 while (!tny_iterator_is_done (iter_all_folders) &&
1803 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1804 TnyFolder *folder = NULL;
1806 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1808 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1809 /* Get a reference to the INBOX */
1810 inbox = g_object_ref (folder);
1812 /* Issue a poke status over the folder */
1814 tny_folder_poke_status (folder);
1817 /* Free and go to next */
1818 g_object_unref (folder);
1819 tny_iterator_next (iter_all_folders);
1821 g_object_unref (iter_all_folders);
1823 /* Refresh the INBOX */
1825 /* Refresh the folder. Our observer receives
1826 * the new emails during folder refreshes, so
1827 * we can use observer->new_headers
1829 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1830 tny_folder_add_observer (inbox, info->inbox_observer);
1832 /* Refresh the INBOX */
1833 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1834 g_object_unref (inbox);
1836 /* We could not perform the inbox refresh but
1837 we'll try to send mails anyway */
1838 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1844 modest_mail_operation_update_account (ModestMailOperation *self,
1845 const gchar *account_name,
1847 gboolean interactive,
1848 RetrieveAllCallback retrieve_all_cb,
1849 UpdateAccountCallback callback,
1852 UpdateAccountInfo *info = NULL;
1853 ModestMailOperationPrivate *priv = NULL;
1854 ModestTnyAccountStore *account_store = NULL;
1856 ModestMailOperationState *state;
1858 /* Init mail operation */
1859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1862 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1863 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1865 /* Get the store account */
1866 account_store = modest_runtime_get_account_store ();
1868 modest_tny_account_store_get_server_account (account_store,
1870 TNY_ACCOUNT_TYPE_STORE);
1872 /* The above function could return NULL */
1873 if (!priv->account) {
1874 /* Check if the operation was a success */
1875 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1876 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1878 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1880 /* Call the user callback */
1882 callback (self, NULL, user_data);
1884 /* Notify about operation end */
1885 modest_mail_operation_notify_end (self);
1890 /* We have once seen priv->account getting finalized during this code,
1891 * therefore adding a reference (bug #82296) */
1893 g_object_ref (priv->account);
1895 /* Create the helper object */
1896 info = g_slice_new0 (UpdateAccountInfo);
1897 info->pending_calls = 1;
1898 info->folders = tny_simple_list_new ();
1899 info->mail_op = g_object_ref (self);
1900 info->poke_all = poke_all;
1901 info->interactive = interactive;
1902 info->account_name = g_strdup (account_name);
1903 info->callback = callback;
1904 info->user_data = user_data;
1905 info->retrieve_all_cb = retrieve_all_cb;
1907 /* Set account busy */
1908 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1909 modest_mail_operation_notify_start (self);
1911 /* notify about the start of the operation */
1912 state = modest_mail_operation_clone_state (self);
1916 /* Start notifying progress */
1917 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1918 g_slice_free (ModestMailOperationState, state);
1920 /* Get all folders and continue in the callback */
1921 folders = tny_simple_list_new ();
1922 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1923 folders, NULL, FALSE,
1924 recurse_folders_async_cb,
1926 g_object_unref (folders);
1928 g_object_unref (priv->account);
1933 * Used to notify the queue from the main
1934 * loop. We call it inside an idle call to achieve that
1937 idle_notify_queue (gpointer data)
1939 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1941 gdk_threads_enter ();
1942 modest_mail_operation_notify_end (mail_op);
1943 gdk_threads_leave ();
1944 g_object_unref (mail_op);
1950 compare_headers_by_date (gconstpointer a,
1953 TnyHeader **header1, **header2;
1954 time_t sent1, sent2;
1956 header1 = (TnyHeader **) a;
1957 header2 = (TnyHeader **) b;
1959 sent1 = tny_header_get_date_sent (*header1);
1960 sent2 = tny_header_get_date_sent (*header2);
1962 /* We want the most recent ones (greater time_t) at the
1971 /* ******************************************************************* */
1972 /* ************************** STORE ACTIONS ************************* */
1973 /* ******************************************************************* */
1976 ModestMailOperation *mail_op;
1977 CreateFolderUserCallback callback;
1983 create_folder_cb (TnyFolderStore *parent_folder,
1985 TnyFolder *new_folder,
1989 ModestMailOperationPrivate *priv;
1990 CreateFolderInfo *info;
1992 info = (CreateFolderInfo *) user_data;
1993 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1995 if (canceled || err) {
1996 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1998 priv->error = g_error_copy (err);
2000 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2001 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2004 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2007 /* The user will unref the new_folder */
2009 info->callback (info->mail_op, parent_folder,
2010 new_folder, info->user_data);
2012 /* Notify about operation end */
2013 modest_mail_operation_notify_end (info->mail_op);
2016 g_object_unref (info->mail_op);
2017 g_slice_free (CreateFolderInfo, info);
2021 modest_mail_operation_create_folder (ModestMailOperation *self,
2022 TnyFolderStore *parent,
2024 CreateFolderUserCallback callback,
2027 ModestMailOperationPrivate *priv;
2029 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2030 g_return_if_fail (name);
2032 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2033 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2034 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2035 g_object_ref (parent) :
2036 modest_tny_folder_get_account (TNY_FOLDER (parent));
2038 /* Check for already existing folder */
2039 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2040 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2041 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2042 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2043 _CS("ckdg_ib_folder_already_exists"));
2047 if (TNY_IS_FOLDER (parent)) {
2048 /* Check folder rules */
2049 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2050 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2051 /* Set status failed and set an error */
2052 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2054 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2055 _("mail_in_ui_folder_create_error"));
2059 if (!strcmp (name, " ") || strchr (name, '/')) {
2060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2062 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2063 _("mail_in_ui_folder_create_error"));
2067 CreateFolderInfo *info;
2069 info = g_slice_new0 (CreateFolderInfo);
2070 info->mail_op = g_object_ref (self);
2071 info->callback = callback;
2072 info->user_data = user_data;
2074 modest_mail_operation_notify_start (self);
2076 /* Create the folder */
2077 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2080 /* Call the user callback anyway */
2082 callback (self, parent, NULL, user_data);
2083 /* Notify about operation end */
2084 modest_mail_operation_notify_end (self);
2089 modest_mail_operation_remove_folder (ModestMailOperation *self,
2091 gboolean remove_to_trash)
2093 ModestMailOperationPrivate *priv;
2094 ModestTnyFolderRules rules;
2096 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2097 g_return_if_fail (TNY_IS_FOLDER (folder));
2099 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2101 /* Check folder rules */
2102 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2103 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2104 /* Set status failed and set an error */
2105 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2106 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2107 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2108 _("mail_in_ui_folder_delete_error"));
2112 /* Get the account */
2113 priv->account = modest_tny_folder_get_account (folder);
2114 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2116 /* Delete folder or move to trash */
2117 if (remove_to_trash) {
2118 TnyFolder *trash_folder = NULL;
2119 trash_folder = modest_tny_account_get_special_folder (priv->account,
2120 TNY_FOLDER_TYPE_TRASH);
2121 /* TODO: error_handling */
2123 modest_mail_operation_notify_start (self);
2124 modest_mail_operation_xfer_folder (self, folder,
2125 TNY_FOLDER_STORE (trash_folder),
2127 g_object_unref (trash_folder);
2129 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2132 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2134 modest_mail_operation_notify_start (self);
2135 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2136 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2139 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2141 g_object_unref (parent);
2143 g_warning ("%s: could not get parent folder", __FUNCTION__);
2147 /* Notify about operation end */
2148 modest_mail_operation_notify_end (self);
2152 transfer_folder_status_cb (GObject *obj,
2156 ModestMailOperation *self;
2157 ModestMailOperationPrivate *priv;
2158 ModestMailOperationState *state;
2159 XFerFolderAsyncHelper *helper;
2161 g_return_if_fail (status != NULL);
2163 /* Show only the status information we want */
2164 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2167 helper = (XFerFolderAsyncHelper *) user_data;
2168 g_return_if_fail (helper != NULL);
2170 self = helper->mail_op;
2171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2173 priv->done = status->position;
2174 priv->total = status->of_total;
2176 state = modest_mail_operation_clone_state (self);
2178 /* This is not a GDK lock because we are a Tinymail callback
2179 * which is already GDK locked by Tinymail */
2181 /* no gdk_threads_enter (), CHECKED */
2183 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2185 /* no gdk_threads_leave (), CHECKED */
2187 g_slice_free (ModestMailOperationState, state);
2192 transfer_folder_cb (TnyFolder *folder,
2194 TnyFolderStore *into,
2195 TnyFolder *new_folder,
2199 XFerFolderAsyncHelper *helper;
2200 ModestMailOperation *self = NULL;
2201 ModestMailOperationPrivate *priv = NULL;
2203 helper = (XFerFolderAsyncHelper *) user_data;
2204 g_return_if_fail (helper != NULL);
2206 self = helper->mail_op;
2207 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2210 priv->error = g_error_copy (err);
2212 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2213 } else if (cancelled) {
2214 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2215 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2216 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2217 _("Transference of %s was cancelled."),
2218 tny_folder_get_name (folder));
2221 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2224 /* Notify about operation end */
2225 modest_mail_operation_notify_end (self);
2227 /* If user defined callback function was defined, call it */
2228 if (helper->user_callback) {
2230 /* This is not a GDK lock because we are a Tinymail callback
2231 * which is already GDK locked by Tinymail */
2233 /* no gdk_threads_enter (), CHECKED */
2234 helper->user_callback (self, new_folder, helper->user_data);
2235 /* no gdk_threads_leave () , CHECKED */
2239 g_object_unref (helper->mail_op);
2240 g_slice_free (XFerFolderAsyncHelper, helper);
2245 * This function checks if the new name is a valid name for our local
2246 * folders account. The new name could not be the same than then name
2247 * of any of the mandatory local folders
2249 * We can not rely on tinymail because tinymail does not check the
2250 * name of the virtual folders that the account could have in the case
2251 * that we're doing a rename (because it directly calls Camel which
2252 * knows nothing about our virtual folders).
2254 * In the case of an actual copy/move (i.e. move/copy a folder between
2255 * accounts) tinymail uses the tny_folder_store_create_account which
2256 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2257 * checks the new name of the folder, so this call in that case
2258 * wouldn't be needed. *But* NOTE that if tinymail changes its
2259 * implementation (if folder transfers within the same account is no
2260 * longer implemented as a rename) this call will allow Modest to work
2263 * If the new name is not valid, this function will set the status to
2264 * failed and will set also an error in the mail operation
2267 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2268 TnyFolderStore *into,
2269 const gchar *new_name)
2271 if (TNY_IS_ACCOUNT (into) &&
2272 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2273 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2275 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2276 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2277 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2278 _CS("ckdg_ib_folder_already_exists"));
2285 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2287 TnyFolderStore *parent,
2288 gboolean delete_original,
2289 XferFolderAsyncUserCallback user_callback,
2292 ModestMailOperationPrivate *priv = NULL;
2293 ModestTnyFolderRules parent_rules = 0, rules;
2294 XFerFolderAsyncHelper *helper = NULL;
2295 const gchar *folder_name = NULL;
2296 const gchar *error_msg;
2298 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2299 g_return_if_fail (TNY_IS_FOLDER (folder));
2300 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2303 folder_name = tny_folder_get_name (folder);
2305 /* Set the error msg */
2306 error_msg = _("mail_in_ui_folder_move_target_error");
2308 /* Get account and set it into mail_operation */
2309 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2310 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2311 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2313 /* Get folder rules */
2314 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2315 if (TNY_IS_FOLDER (parent))
2316 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2318 /* Apply operation constraints */
2319 if ((gpointer) parent == (gpointer) folder ||
2320 (!TNY_IS_FOLDER_STORE (parent)) ||
2321 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2324 } else if (TNY_IS_FOLDER (parent) &&
2325 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2329 } else if (TNY_IS_FOLDER (parent) &&
2330 TNY_IS_FOLDER_STORE (folder) &&
2331 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2332 TNY_FOLDER_STORE (folder))) {
2333 /* Do not move a parent into a child */
2335 } else if (TNY_IS_FOLDER_STORE (parent) &&
2336 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2337 /* Check that the new folder name is not used by any
2340 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2341 /* Check that the new folder name is not used by any
2342 special local folder */
2345 /* Create the helper */
2346 helper = g_slice_new0 (XFerFolderAsyncHelper);
2347 helper->mail_op = g_object_ref (self);
2348 helper->user_callback = user_callback;
2349 helper->user_data = user_data;
2351 /* Move/Copy folder */
2352 modest_mail_operation_notify_start (self);
2353 tny_folder_copy_async (folder,
2355 tny_folder_get_name (folder),
2358 transfer_folder_status_cb,
2364 /* Set status failed and set an error */
2365 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2366 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2367 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2370 /* Call the user callback if exists */
2372 user_callback (self, NULL, user_data);
2374 /* Notify the queue */
2375 modest_mail_operation_notify_end (self);
2379 modest_mail_operation_rename_folder (ModestMailOperation *self,
2382 XferFolderAsyncUserCallback user_callback,
2385 ModestMailOperationPrivate *priv;
2386 ModestTnyFolderRules rules;
2387 XFerFolderAsyncHelper *helper;
2389 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2390 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2391 g_return_if_fail (name);
2393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2395 /* Get account and set it into mail_operation */
2396 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2397 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2399 /* Check folder rules */
2400 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2401 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2403 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2406 TnyFolderStore *into;
2408 into = tny_folder_get_folder_store (folder);
2410 /* Check that the new folder name is not used by any
2411 special local folder */
2412 if (new_name_valid_if_local_account (priv, into, name)) {
2413 /* Create the helper */
2414 helper = g_slice_new0 (XFerFolderAsyncHelper);
2415 helper->mail_op = g_object_ref(self);
2416 helper->user_callback = user_callback;
2417 helper->user_data = user_data;
2419 /* Rename. Camel handles folder subscription/unsubscription */
2420 modest_mail_operation_notify_start (self);
2421 tny_folder_copy_async (folder, into, name, TRUE,
2423 transfer_folder_status_cb,
2425 g_object_unref (into);
2427 g_object_unref (into);
2434 /* Set status failed and set an error */
2435 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2436 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2437 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2438 _("FIXME: unable to rename"));
2441 user_callback (self, NULL, user_data);
2443 /* Notify about operation end */
2444 modest_mail_operation_notify_end (self);
2447 /* ******************************************************************* */
2448 /* ************************** MSG ACTIONS ************************* */
2449 /* ******************************************************************* */
2452 modest_mail_operation_get_msg (ModestMailOperation *self,
2454 gboolean progress_feedback,
2455 GetMsgAsyncUserCallback user_callback,
2458 GetMsgInfo *helper = NULL;
2460 ModestMailOperationPrivate *priv;
2462 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2463 g_return_if_fail (TNY_IS_HEADER (header));
2465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2466 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2470 /* Check memory low */
2471 if (_check_memory_low (self)) {
2473 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2474 modest_mail_operation_notify_end (self);
2478 /* Get account and set it into mail_operation */
2479 folder = tny_header_get_folder (header);
2480 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2482 /* Check for cached messages */
2483 if (progress_feedback) {
2484 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2485 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2487 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2489 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2492 /* Create the helper */
2493 helper = g_slice_new0 (GetMsgInfo);
2494 helper->header = g_object_ref (header);
2495 helper->mail_op = g_object_ref (self);
2496 helper->user_callback = user_callback;
2497 helper->user_data = user_data;
2498 helper->destroy_notify = NULL;
2499 helper->last_total_bytes = 0;
2500 helper->sum_total_bytes = 0;
2501 helper->total_bytes = tny_header_get_message_size (header);
2502 helper->more_msgs = NULL;
2504 modest_mail_operation_notify_start (self);
2506 /* notify about the start of the operation */
2507 ModestMailOperationState *state;
2508 state = modest_mail_operation_clone_state (self);
2511 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2513 g_slice_free (ModestMailOperationState, state);
2515 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2517 g_object_unref (G_OBJECT (folder));
2521 get_msg_status_cb (GObject *obj,
2525 GetMsgInfo *helper = NULL;
2527 g_return_if_fail (status != NULL);
2529 /* Show only the status information we want */
2530 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2533 helper = (GetMsgInfo *) user_data;
2534 g_return_if_fail (helper != NULL);
2536 /* Notify progress */
2537 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2538 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2542 get_msg_async_cb (TnyFolder *folder,
2548 GetMsgInfo *info = NULL;
2549 ModestMailOperationPrivate *priv = NULL;
2552 info = (GetMsgInfo *) user_data;
2554 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2557 if (info->more_msgs) {
2558 tny_iterator_next (info->more_msgs);
2559 finished = (tny_iterator_is_done (info->more_msgs));
2561 finished = (priv->done == priv->total) ? TRUE : FALSE;
2564 /* If canceled by the user, ignore the error given by Tinymail */
2568 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2570 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2572 priv->error = g_error_copy ((const GError *) err);
2573 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2576 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2577 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2580 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2581 /* Set the success status before calling the user callback */
2582 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2586 /* Call the user callback */
2587 if (info->user_callback)
2588 info->user_callback (info->mail_op, info->header, canceled,
2589 msg, err, info->user_data);
2591 /* Notify about operation end if this is the last callback */
2593 /* Free user data */
2594 if (info->destroy_notify)
2595 info->destroy_notify (info->user_data);
2597 /* Notify about operation end */
2598 modest_mail_operation_notify_end (info->mail_op);
2601 if (info->more_msgs)
2602 g_object_unref (info->more_msgs);
2603 g_object_unref (info->header);
2604 g_object_unref (info->mail_op);
2605 g_slice_free (GetMsgInfo, info);
2606 } else if (info->more_msgs) {
2607 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2608 TnyFolder *folder = tny_header_get_folder (header);
2610 g_object_unref (info->header);
2611 info->header = g_object_ref (header);
2613 /* Retrieve the next message */
2614 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2616 g_object_unref (header);
2617 g_object_unref (folder);
2619 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2624 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2625 TnyList *header_list,
2626 GetMsgAsyncUserCallback user_callback,
2628 GDestroyNotify notify)
2630 ModestMailOperationPrivate *priv = NULL;
2632 TnyIterator *iter = NULL;
2633 gboolean has_uncached_messages;
2635 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2637 /* Init mail operation */
2638 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2639 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2641 priv->total = tny_list_get_length(header_list);
2643 /* Check memory low */
2644 if (_check_memory_low (self)) {
2645 if (user_callback) {
2646 TnyHeader *header = NULL;
2649 if (tny_list_get_length (header_list) > 0) {
2650 iter = tny_list_create_iterator (header_list);
2651 header = (TnyHeader *) tny_iterator_get_current (iter);
2652 g_object_unref (iter);
2654 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2656 g_object_unref (header);
2660 /* Notify about operation end */
2661 modest_mail_operation_notify_end (self);
2665 /* Check uncached messages */
2666 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2667 !has_uncached_messages && !tny_iterator_is_done (iter);
2668 tny_iterator_next (iter)) {
2671 header = (TnyHeader *) tny_iterator_get_current (iter);
2672 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2673 has_uncached_messages = TRUE;
2674 g_object_unref (header);
2676 g_object_unref (iter);
2677 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2679 /* Get account and set it into mail_operation */
2680 if (tny_list_get_length (header_list) >= 1) {
2681 TnyIterator *iterator = tny_list_create_iterator (header_list);
2682 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2684 TnyFolder *folder = tny_header_get_folder (header);
2686 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2687 g_object_unref (folder);
2689 g_object_unref (header);
2691 g_object_unref (iterator);
2694 msg_list_size = compute_message_list_size (header_list, 0);
2696 modest_mail_operation_notify_start (self);
2697 iter = tny_list_create_iterator (header_list);
2698 if (!tny_iterator_is_done (iter)) {
2699 /* notify about the start of the operation */
2700 ModestMailOperationState *state;
2701 state = modest_mail_operation_clone_state (self);
2704 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2707 GetMsgInfo *msg_info = NULL;
2708 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2709 TnyFolder *folder = tny_header_get_folder (header);
2711 /* Create the message info */
2712 msg_info = g_slice_new0 (GetMsgInfo);
2713 msg_info->mail_op = g_object_ref (self);
2714 msg_info->header = g_object_ref (header);
2715 msg_info->more_msgs = g_object_ref (iter);
2716 msg_info->user_callback = user_callback;
2717 msg_info->user_data = user_data;
2718 msg_info->destroy_notify = notify;
2719 msg_info->last_total_bytes = 0;
2720 msg_info->sum_total_bytes = 0;
2721 msg_info->total_bytes = msg_list_size;
2723 /* The callback will call it per each header */
2724 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2726 /* Free and go on */
2727 g_object_unref (header);
2728 g_object_unref (folder);
2729 g_slice_free (ModestMailOperationState, state);
2731 g_object_unref (iter);
2736 remove_msgs_async_cb (TnyFolder *folder,
2741 gboolean expunge, leave_on_server;
2742 const gchar *account_name;
2743 TnyAccount *account;
2744 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2745 ModestMailOperation *self;
2746 ModestMailOperationPrivate *priv;
2747 ModestProtocolRegistry *protocol_registry;
2749 self = (ModestMailOperation *) user_data;
2750 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2751 protocol_registry = modest_runtime_get_protocol_registry ();
2753 if (canceled || err) {
2754 /* If canceled by the user, ignore the error given by Tinymail */
2756 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2758 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2759 priv->error = g_error_copy ((const GError *) err);
2760 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2763 modest_mail_operation_notify_end (self);
2764 g_object_unref (self);
2768 account = tny_folder_get_account (folder);
2769 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2771 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2773 account_proto = modest_tny_account_get_protocol_type (account);
2774 g_object_unref (account);
2776 if ((modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) &&
2777 !leave_on_server) ||
2778 !modest_tny_folder_is_remote_folder (folder))
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");