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-defs.h>
49 #include "modest-platform.h"
50 #include "modest-account-mgr-helpers.h"
51 #include <modest-tny-account.h>
52 #include <modest-tny-send-queue.h>
53 #include <modest-runtime.h>
54 #include "modest-text-utils.h"
55 #include "modest-tny-msg.h"
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account-store.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-marshal.h"
60 #include "modest-error.h"
61 #include "modest-mail-operation.h"
62 #include <modest-count-stream.h>
63 #include <libgnomevfs/gnome-vfs.h>
64 #include "modest-utils.h"
65 #include "modest-debug.h"
70 * Remove all these #ifdef stuff when the tinymail's idle calls become
73 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
75 /* 'private'/'protected' functions */
76 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
77 static void modest_mail_operation_init (ModestMailOperation *obj);
78 static void modest_mail_operation_finalize (GObject *obj);
80 static void get_msg_async_cb (TnyFolder *folder,
86 static void get_msg_status_cb (GObject *obj,
90 static void modest_mail_operation_notify_start (ModestMailOperation *self);
91 static void modest_mail_operation_notify_end (ModestMailOperation *self);
93 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
95 gint *last_total_bytes,
96 gint *sum_total_bytes,
98 gboolean increment_done);
100 static guint compute_message_list_size (TnyList *headers, guint num_elements);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 static gboolean _check_memory_low (ModestMailOperation *mail_op);
114 ModestTnySendQueue *queue;
115 ModestMailOperation *self;
121 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
122 ModestMailOperationStatus status);
124 /* Helpers for the update account operation (send & receive)*/
127 ModestMailOperation *mail_op;
129 UpdateAccountCallback callback;
134 TnyFolderObserver *inbox_observer;
135 RetrieveAllCallback retrieve_all_cb;
136 gboolean interactive;
140 static void destroy_update_account_info (UpdateAccountInfo *info);
142 static void update_account_send_mail (UpdateAccountInfo *info);
144 static void update_account_get_msg_async_cb (TnyFolder *folder,
150 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
151 TnyList *new_headers);
153 enum _ModestMailOperationSignals
155 PROGRESS_CHANGED_SIGNAL,
156 OPERATION_STARTED_SIGNAL,
157 OPERATION_FINISHED_SIGNAL,
161 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
162 struct _ModestMailOperationPrivate {
168 ErrorCheckingUserCallback error_checking;
169 gpointer error_checking_user_data;
170 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
171 ModestMailOperationStatus status;
172 ModestMailOperationTypeOperation op_type;
175 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
176 MODEST_TYPE_MAIL_OPERATION, \
177 ModestMailOperationPrivate))
179 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
180 priv->status = new_status;\
185 GetMsgAsyncUserCallback user_callback;
187 TnyIterator *more_msgs;
189 ModestMailOperation *mail_op;
190 GDestroyNotify destroy_notify;
191 gint last_total_bytes;
192 gint sum_total_bytes;
196 typedef struct _RefreshAsyncHelper {
197 ModestMailOperation *mail_op;
198 RefreshAsyncUserCallback user_callback;
200 } RefreshAsyncHelper;
202 typedef struct _XFerMsgsAsyncHelper
204 ModestMailOperation *mail_op;
206 TnyIterator *more_msgs;
207 TnyFolder *dest_folder;
208 XferMsgsAsyncUserCallback user_callback;
211 gint last_total_bytes;
212 gint sum_total_bytes;
214 } XFerMsgsAsyncHelper;
216 typedef struct _XFerFolderAsyncHelper
218 ModestMailOperation *mail_op;
219 XferFolderAsyncUserCallback user_callback;
221 } XFerFolderAsyncHelper;
223 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
227 static void modest_mail_operation_create_msg (ModestMailOperation *self,
228 const gchar *from, const gchar *to,
229 const gchar *cc, const gchar *bcc,
230 const gchar *subject, const gchar *plain_body,
231 const gchar *html_body, const GList *attachments_list,
232 const GList *images_list,
233 TnyHeaderFlags priority_flags,
234 const gchar *references, const gchar *in_reply_to,
235 ModestMailOperationCreateMsgCallback callback,
238 static gboolean idle_notify_queue (gpointer data);
241 ModestMailOperation *mail_op;
251 GList *attachments_list;
253 TnyHeaderFlags priority_flags;
254 ModestMailOperationCreateMsgCallback callback;
260 ModestMailOperation *mail_op;
262 ModestMailOperationCreateMsgCallback callback;
267 static GObjectClass *parent_class = NULL;
269 static guint signals[NUM_SIGNALS] = {0};
272 modest_mail_operation_get_type (void)
274 static GType my_type = 0;
276 static const GTypeInfo my_info = {
277 sizeof(ModestMailOperationClass),
278 NULL, /* base init */
279 NULL, /* base finalize */
280 (GClassInitFunc) modest_mail_operation_class_init,
281 NULL, /* class finalize */
282 NULL, /* class data */
283 sizeof(ModestMailOperation),
285 (GInstanceInitFunc) modest_mail_operation_init,
288 my_type = g_type_register_static (G_TYPE_OBJECT,
289 "ModestMailOperation",
296 modest_mail_operation_class_init (ModestMailOperationClass *klass)
298 GObjectClass *gobject_class;
299 gobject_class = (GObjectClass*) klass;
301 parent_class = g_type_class_peek_parent (klass);
302 gobject_class->finalize = modest_mail_operation_finalize;
304 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
307 * ModestMailOperation::progress-changed
308 * @self: the #MailOperation that emits the signal
309 * @user_data: user data set when the signal handler was connected
311 * Emitted when the progress of a mail operation changes
313 signals[PROGRESS_CHANGED_SIGNAL] =
314 g_signal_new ("progress-changed",
315 G_TYPE_FROM_CLASS (gobject_class),
317 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
319 g_cclosure_marshal_VOID__POINTER,
320 G_TYPE_NONE, 1, G_TYPE_POINTER);
324 * This signal is issued whenever a mail operation starts, and
325 * starts mean when the tinymail operation is issued. This
326 * means that it could happen that something wrong happens and
327 * the tinymail function is never called. In this situation a
328 * operation-finished will be issued without any
331 signals[OPERATION_STARTED_SIGNAL] =
332 g_signal_new ("operation-started",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
337 g_cclosure_marshal_VOID__VOID,
342 * This signal is issued whenever a mail operation
343 * finishes. Note that this signal could be issued without any
344 * previous "operation-started" signal, because this last one
345 * is only issued when the tinymail operation is successfully
348 signals[OPERATION_FINISHED_SIGNAL] =
349 g_signal_new ("operation-finished",
350 G_TYPE_FROM_CLASS (gobject_class),
352 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
354 g_cclosure_marshal_VOID__VOID,
359 modest_mail_operation_init (ModestMailOperation *obj)
361 ModestMailOperationPrivate *priv;
363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
365 priv->account = NULL;
366 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
367 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
372 priv->error_checking = NULL;
373 priv->error_checking_user_data = NULL;
377 modest_mail_operation_finalize (GObject *obj)
379 ModestMailOperationPrivate *priv;
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
386 g_error_free (priv->error);
390 g_object_unref (priv->source);
394 g_object_unref (priv->account);
395 priv->account = NULL;
399 G_OBJECT_CLASS(parent_class)->finalize (obj);
403 modest_mail_operation_new (GObject *source)
405 ModestMailOperation *obj;
406 ModestMailOperationPrivate *priv;
408 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 priv->source = g_object_ref(source);
418 modest_mail_operation_new_with_error_handling (GObject *source,
419 ErrorCheckingUserCallback error_handler,
421 ErrorCheckingUserDataDestroyer error_handler_destroyer)
423 ModestMailOperation *obj;
424 ModestMailOperationPrivate *priv;
426 obj = modest_mail_operation_new (source);
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
429 g_return_val_if_fail (error_handler != NULL, obj);
430 priv->error_checking = error_handler;
431 priv->error_checking_user_data = user_data;
432 priv->error_checking_user_data_destroyer = error_handler_destroyer;
438 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
445 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
447 /* Call the user callback */
448 if (priv->error_checking != NULL)
449 priv->error_checking (self, priv->error_checking_user_data);
453 ModestMailOperationTypeOperation
454 modest_mail_operation_get_type_operation (ModestMailOperation *self)
456 ModestMailOperationPrivate *priv;
458 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
459 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
463 return priv->op_type;
467 modest_mail_operation_is_mine (ModestMailOperation *self,
470 ModestMailOperationPrivate *priv;
472 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
475 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
476 if (priv->source == NULL) return FALSE;
478 return priv->source == me;
482 modest_mail_operation_get_source (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
491 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
495 return (priv->source) ? g_object_ref (priv->source) : NULL;
498 ModestMailOperationStatus
499 modest_mail_operation_get_status (ModestMailOperation *self)
501 ModestMailOperationPrivate *priv;
503 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
504 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
505 MODEST_MAIL_OPERATION_STATUS_INVALID);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
509 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
510 return MODEST_MAIL_OPERATION_STATUS_INVALID;
517 modest_mail_operation_get_error (ModestMailOperation *self)
519 ModestMailOperationPrivate *priv;
521 g_return_val_if_fail (self, NULL);
522 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
527 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
535 modest_mail_operation_cancel (ModestMailOperation *self)
537 ModestMailOperationPrivate *priv;
538 gboolean canceled = FALSE;
540 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
542 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
547 /* Cancel the mail operation */
548 g_return_val_if_fail (priv->account, FALSE);
549 tny_account_cancel (priv->account);
551 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
552 ModestTnySendQueue *queue;
553 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
556 /* Cancel the sending of the following next messages */
557 if (TNY_IS_SEND_QUEUE (queue))
558 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
565 modest_mail_operation_get_task_done (ModestMailOperation *self)
567 ModestMailOperationPrivate *priv;
569 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
577 modest_mail_operation_get_task_total (ModestMailOperation *self)
579 ModestMailOperationPrivate *priv;
581 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
589 modest_mail_operation_is_finished (ModestMailOperation *self)
591 ModestMailOperationPrivate *priv;
592 gboolean retval = FALSE;
594 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
599 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
600 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
601 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
602 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
612 * Creates an image of the current state of a mail operation, the
613 * caller must free it
615 static ModestMailOperationState *
616 modest_mail_operation_clone_state (ModestMailOperation *self)
618 ModestMailOperationState *state;
619 ModestMailOperationPrivate *priv;
621 g_return_val_if_fail (self, NULL);
622 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
623 g_return_val_if_fail (priv, NULL);
628 state = g_slice_new (ModestMailOperationState);
630 state->status = priv->status;
631 state->op_type = priv->op_type;
632 state->done = priv->done;
633 state->total = priv->total;
634 state->finished = modest_mail_operation_is_finished (self);
635 state->bytes_done = 0;
636 state->bytes_total = 0;
641 /* ******************************************************************* */
642 /* ************************** SEND ACTIONS ************************* */
643 /* ******************************************************************* */
647 ModestMailOperation *mail_op;
652 send_mail_on_sync_async_cb (TnyFolder *folder,
657 ModestMailOperationPrivate *priv;
658 ModestMailOperation *self;
659 SendNewMailHelper *helper;
661 helper = (SendNewMailHelper *) user_data;
662 self = helper->mail_op;
663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
665 if (cancelled || err)
669 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
670 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
671 "Error adding a msg to the send queue\n");
672 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
674 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
679 modest_mail_operation_notify_end (self);
681 g_object_unref (helper->mail_op);
682 g_slice_free (SendNewMailHelper, helper);
686 run_queue_start (TnySendQueue *self,
689 RunQueueHelper *helper = (RunQueueHelper *) user_data;
690 ModestMailOperation *mail_op;
692 g_debug ("%s sending queue successfully started", __FUNCTION__);
694 /* Wait for the message to be sent */
695 mail_op = modest_mail_operation_new (NULL);
696 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
698 modest_mail_operation_run_queue (mail_op, helper->queue);
699 g_object_unref (mail_op);
701 /* Free the helper and end operation */
702 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
706 run_queue_error_happened (TnySendQueue *queue,
712 RunQueueHelper *helper = (RunQueueHelper *) user_data;
713 ModestMailOperationPrivate *priv;
715 /* If we are here this means that the send queue could not
716 start to send emails. Shouldn't happen as this means that
717 we could not create the thread */
718 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
721 priv->error = g_error_copy ((const GError *) error);
723 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
724 /* This code is here for safety reasons. It should
725 never be called, because that would mean that we
726 are not controlling some error case */
727 g_warning ("%s Error %s should not happen",
728 __FUNCTION__, error->message);
731 /* Free helper and end operation */
732 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
736 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
742 ModestMailOperationPrivate *priv;
743 ModestMailOperation *self;
744 SendNewMailHelper *helper;
746 helper = (SendNewMailHelper *) user_data;
747 self = helper->mail_op;
748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
750 if (cancelled || err)
754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
755 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
756 "Error adding a msg to the send queue\n");
757 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
759 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
763 if (helper->notify) {
764 TnyTransportAccount *trans_account;
765 ModestTnySendQueue *queue;
767 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
769 queue = modest_runtime_get_send_queue (trans_account, TRUE);
771 RunQueueHelper *helper;
773 /* Create the helper */
774 helper = g_slice_new0 (RunQueueHelper);
775 helper->queue = g_object_ref (queue);
776 helper->self = g_object_ref (self);
778 /* if sending is ongoing wait for the queue to
779 stop. Otherwise wait for the queue-start
780 signal. It could happen that the queue
781 could not start, then check also the error
783 if (modest_tny_send_queue_sending_in_progress (queue)) {
784 run_queue_start (TNY_SEND_QUEUE (queue), helper);
786 helper->start_handler = g_signal_connect (queue, "queue-start",
787 G_CALLBACK (run_queue_start),
789 helper->error_handler = g_signal_connect (queue, "error-happened",
790 G_CALLBACK (run_queue_error_happened),
794 /* Finalize this mail operation */
795 modest_mail_operation_notify_end (self);
797 g_object_unref (trans_account);
799 g_warning ("No transport account for the operation");
803 g_object_unref (helper->mail_op);
804 g_slice_free (SendNewMailHelper, helper);
808 idle_create_msg_cb (gpointer idle_data)
810 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
812 /* This is a GDK lock because we are an idle callback and
813 * info->callback can contain Gtk+ code */
815 gdk_threads_enter (); /* CHECKED */
816 info->callback (info->mail_op, info->msg, info->userdata);
818 g_object_unref (info->mail_op);
820 g_object_unref (info->msg);
821 g_slice_free (CreateMsgIdleInfo, info);
822 gdk_threads_leave (); /* CHECKED */
828 create_msg_thread (gpointer thread_data)
830 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
831 TnyMsg *new_msg = NULL;
832 ModestMailOperationPrivate *priv;
835 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
836 if (info->html_body == NULL) {
837 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
838 info->bcc, info->subject,
839 info->references, info->in_reply_to,
841 info->attachments_list, &attached,
844 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
845 info->bcc, info->subject,
846 info->references, info->in_reply_to,
848 info->plain_body, info->attachments_list,
849 info->images_list, &attached,
856 /* Set priority flags in message */
857 header = tny_msg_get_header (new_msg);
858 tny_header_set_flag (header, info->priority_flags);
860 /* Set attachment flags in message */
861 if (info->attachments_list != NULL && attached > 0)
862 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
864 g_object_unref (G_OBJECT(header));
866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
868 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
869 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
870 "modest: failed to create a new msg\n");
878 g_free (info->plain_body);
879 g_free (info->html_body);
880 g_free (info->subject);
881 g_free (info->references);
882 g_free (info->in_reply_to);
883 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
884 g_list_free (info->attachments_list);
885 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
886 g_list_free (info->images_list);
888 if (info->callback) {
889 CreateMsgIdleInfo *idle_info;
890 idle_info = g_slice_new0 (CreateMsgIdleInfo);
891 idle_info->mail_op = g_object_ref (info->mail_op);
892 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
893 idle_info->callback = info->callback;
894 idle_info->userdata = info->userdata;
895 g_idle_add (idle_create_msg_cb, idle_info);
897 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
900 g_object_unref (info->mail_op);
901 g_slice_free (CreateMsgInfo, info);
902 if (new_msg) g_object_unref(new_msg);
908 modest_mail_operation_create_msg (ModestMailOperation *self,
909 const gchar *from, const gchar *to,
910 const gchar *cc, const gchar *bcc,
911 const gchar *subject, const gchar *plain_body,
912 const gchar *html_body,
913 const GList *attachments_list,
914 const GList *images_list,
915 TnyHeaderFlags priority_flags,
916 const gchar *references,
917 const gchar *in_reply_to,
918 ModestMailOperationCreateMsgCallback callback,
921 CreateMsgInfo *info = NULL;
923 info = g_slice_new0 (CreateMsgInfo);
924 info->mail_op = g_object_ref (self);
926 info->from = g_strdup (from);
927 info->to = g_strdup (to);
928 info->cc = g_strdup (cc);
929 info->bcc = g_strdup (bcc);
930 info->subject = g_strdup (subject);
931 info->plain_body = g_strdup (plain_body);
932 info->html_body = g_strdup (html_body);
933 info->references = g_strdup (references);
934 info->in_reply_to = g_strdup (in_reply_to);
935 info->attachments_list = g_list_copy ((GList *) attachments_list);
936 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
937 info->images_list = g_list_copy ((GList *) images_list);
938 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
939 info->priority_flags = priority_flags;
941 info->callback = callback;
942 info->userdata = userdata;
944 g_thread_create (create_msg_thread, info, FALSE, NULL);
949 TnyTransportAccount *transport_account;
954 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
958 TnySendQueue *send_queue = NULL;
959 ModestMailOperationPrivate *priv = NULL;
960 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
961 TnyFolder *draft_folder = NULL;
962 TnyFolder *outbox_folder = NULL;
963 TnyHeader *header = NULL;
965 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
968 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
969 modest_mail_operation_notify_end (self);
973 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
974 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
975 modest_mail_operation_notify_end (self);
979 /* Add message to send queue */
980 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
981 if (!TNY_IS_SEND_QUEUE(send_queue)) {
983 g_error_free (priv->error);
986 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
987 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
988 "modest: could not find send queue for account\n");
989 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
990 modest_mail_operation_notify_end (self);
993 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
994 helper->mail_op = g_object_ref (self);
995 helper->notify = (info->draft_msg == NULL);
997 /* Add the msg to the queue. The callback will free
999 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1001 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1005 if (info->draft_msg != NULL) {
1006 TnyList *tmp_headers = NULL;
1007 TnyFolder *folder = NULL;
1008 TnyFolder *src_folder = NULL;
1009 TnyFolderType folder_type;
1010 TnyTransportAccount *transport_account = NULL;
1011 SendNewMailHelper *helper = NULL;
1013 /* To remove the old mail from its source folder, we need to get the
1014 * transport account of the original draft message (the transport account
1015 * might have been changed by the user) */
1016 header = tny_msg_get_header (info->draft_msg);
1017 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1018 modest_runtime_get_account_store(), header);
1019 if (transport_account == NULL)
1020 transport_account = g_object_ref(info->transport_account);
1021 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1022 TNY_FOLDER_TYPE_DRAFTS);
1023 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1024 TNY_FOLDER_TYPE_OUTBOX);
1025 g_object_unref(transport_account);
1027 if (!draft_folder) {
1028 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1030 modest_mail_operation_notify_end (self);
1033 if (!outbox_folder) {
1034 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1036 modest_mail_operation_notify_end (self);
1040 folder = tny_msg_get_folder (info->draft_msg);
1041 if (folder == NULL) {
1042 modest_mail_operation_notify_end (self);
1045 folder_type = modest_tny_folder_guess_folder_type (folder);
1047 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1048 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1050 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1051 src_folder = outbox_folder;
1053 src_folder = draft_folder;
1055 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1056 * because this function requires it to have a UID. */
1057 helper = g_slice_new (SendNewMailHelper);
1058 helper->mail_op = g_object_ref (self);
1059 helper->notify = TRUE;
1061 tmp_headers = tny_simple_list_new ();
1062 tny_list_append (tmp_headers, (GObject*) header);
1063 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1064 g_object_unref (tmp_headers);
1065 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1067 g_object_unref (folder);
1072 g_object_unref (header);
1073 if (info->draft_msg)
1074 g_object_unref (info->draft_msg);
1076 g_object_unref (draft_folder);
1078 g_object_unref (outbox_folder);
1079 if (info->transport_account)
1080 g_object_unref (info->transport_account);
1081 g_slice_free (SendNewMailInfo, info);
1085 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1086 TnyTransportAccount *transport_account,
1088 const gchar *from, const gchar *to,
1089 const gchar *cc, const gchar *bcc,
1090 const gchar *subject, const gchar *plain_body,
1091 const gchar *html_body,
1092 const GList *attachments_list,
1093 const GList *images_list,
1094 const gchar *references,
1095 const gchar *in_reply_to,
1096 TnyHeaderFlags priority_flags)
1098 ModestMailOperationPrivate *priv = NULL;
1099 SendNewMailInfo *info;
1101 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1102 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1105 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1106 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1107 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1109 modest_mail_operation_notify_start (self);
1111 /* Check parametters */
1113 /* Set status failed and set an error */
1114 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1115 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1116 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1117 _("Error trying to send a mail. You need to set at least one recipient"));
1118 modest_mail_operation_notify_end (self);
1121 info = g_slice_new0 (SendNewMailInfo);
1122 info->transport_account = transport_account;
1123 if (transport_account)
1124 g_object_ref (transport_account);
1125 info->draft_msg = draft_msg;
1127 g_object_ref (draft_msg);
1130 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1131 attachments_list, images_list, priority_flags,
1132 references, in_reply_to,
1133 modest_mail_operation_send_new_mail_cb, info);
1139 TnyTransportAccount *transport_account;
1141 SaveToDraftstCallback callback;
1145 ModestMailOperation *mailop;
1146 } SaveToDraftsAddMsgInfo;
1149 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1154 ModestMailOperationPrivate *priv = NULL;
1155 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1156 GError *io_error = NULL;
1158 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1160 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1161 io_error = priv->error;
1165 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1166 g_error_free(priv->error);
1169 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1171 if ((!priv->error) && (info->draft_msg != NULL)) {
1172 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1173 TnyFolder *src_folder = tny_header_get_folder (header);
1175 g_debug ("--- REMOVE AND SYNC");
1176 /* Remove the old draft */
1177 tny_folder_remove_msg (src_folder, header, NULL);
1179 /* Synchronize to expunge and to update the msg counts */
1180 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1181 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1182 g_debug ("--- REMOVED - SYNCED");
1184 g_object_unref (G_OBJECT(header));
1185 g_object_unref (G_OBJECT(src_folder));
1189 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1191 g_error_free (io_error);
1194 } else if (io_error) {
1195 priv->error = io_error;
1196 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1198 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1201 /* Call the user callback */
1203 info->callback (info->mailop, info->msg, info->user_data);
1205 if (info->transport_account)
1206 g_object_unref (G_OBJECT(info->transport_account));
1207 if (info->draft_msg)
1208 g_object_unref (G_OBJECT (info->draft_msg));
1210 g_object_unref (G_OBJECT(info->drafts));
1212 g_object_unref (G_OBJECT (info->msg));
1214 modest_mail_operation_notify_end (info->mailop);
1215 g_object_unref(info->mailop);
1216 g_slice_free (SaveToDraftsAddMsgInfo, info);
1221 TnyTransportAccount *transport_account;
1223 SaveToDraftstCallback callback;
1228 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1232 TnyFolder *drafts = NULL;
1233 ModestMailOperationPrivate *priv = NULL;
1234 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1239 if (!(priv->error)) {
1240 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1241 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1242 "modest: failed to create a new msg\n");
1245 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1246 TNY_FOLDER_TYPE_DRAFTS);
1247 if (!drafts && !(priv->error)) {
1248 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1249 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1250 "modest: failed to create a new msg\n");
1254 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1256 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1257 cb_info->transport_account = g_object_ref(info->transport_account);
1258 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1259 cb_info->callback = info->callback;
1260 cb_info->user_data = info->user_data;
1261 cb_info->drafts = g_object_ref(drafts);
1262 cb_info->msg = g_object_ref(msg);
1263 cb_info->mailop = g_object_ref(self);
1264 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1268 /* Call the user callback */
1269 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1271 info->callback (self, msg, info->user_data);
1272 modest_mail_operation_notify_end (self);
1276 g_object_unref (G_OBJECT(drafts));
1277 if (info->draft_msg)
1278 g_object_unref (G_OBJECT (info->draft_msg));
1279 if (info->transport_account)
1280 g_object_unref (G_OBJECT(info->transport_account));
1281 g_slice_free (SaveToDraftsInfo, info);
1285 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1286 TnyTransportAccount *transport_account,
1288 const gchar *from, const gchar *to,
1289 const gchar *cc, const gchar *bcc,
1290 const gchar *subject, const gchar *plain_body,
1291 const gchar *html_body,
1292 const GList *attachments_list,
1293 const GList *images_list,
1294 TnyHeaderFlags priority_flags,
1295 const gchar *references,
1296 const gchar *in_reply_to,
1297 SaveToDraftstCallback callback,
1300 ModestMailOperationPrivate *priv = NULL;
1301 SaveToDraftsInfo *info = NULL;
1303 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1304 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1308 /* Get account and set it into mail_operation */
1309 priv->account = g_object_ref (transport_account);
1310 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1312 info = g_slice_new0 (SaveToDraftsInfo);
1313 info->transport_account = g_object_ref (transport_account);
1314 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1315 info->callback = callback;
1316 info->user_data = user_data;
1318 g_debug ("--- CREATE MESSAGE");
1319 modest_mail_operation_notify_start (self);
1320 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1321 attachments_list, images_list, priority_flags,
1322 references, in_reply_to,
1323 modest_mail_operation_save_to_drafts_cb, info);
1328 ModestMailOperation *mail_op;
1329 TnyMimePart *mime_part;
1331 GetMimePartSizeCallback callback;
1333 } GetMimePartSizeInfo;
1335 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1336 /* We use this folder observer to track the headers that have been
1337 * added to a folder */
1340 TnyList *new_headers;
1341 } InternalFolderObserver;
1344 GObjectClass parent;
1345 } InternalFolderObserverClass;
1347 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1349 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1350 internal_folder_observer,
1352 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1356 foreach_add_item (gpointer header, gpointer user_data)
1358 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1361 /* This is the method that looks for new messages in a folder */
1363 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1365 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1367 TnyFolderChangeChanged changed;
1369 changed = tny_folder_change_get_changed (change);
1371 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1374 /* Get added headers */
1375 list = tny_simple_list_new ();
1376 tny_folder_change_get_added_headers (change, list);
1378 /* Add them to the folder observer */
1379 tny_list_foreach (list, foreach_add_item,
1380 derived->new_headers);
1382 g_object_unref (G_OBJECT (list));
1387 internal_folder_observer_init (InternalFolderObserver *self)
1389 self->new_headers = tny_simple_list_new ();
1392 internal_folder_observer_finalize (GObject *object)
1394 InternalFolderObserver *self;
1396 self = (InternalFolderObserver *) object;
1397 g_object_unref (self->new_headers);
1399 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1402 tny_folder_observer_init (TnyFolderObserverIface *iface)
1404 iface->update = internal_folder_observer_update;
1407 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1409 GObjectClass *object_class;
1411 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1412 object_class = (GObjectClass*) klass;
1413 object_class->finalize = internal_folder_observer_finalize;
1417 destroy_update_account_info (UpdateAccountInfo *info)
1419 g_free (info->account_name);
1420 g_object_unref (info->folders);
1421 g_object_unref (info->mail_op);
1422 g_slice_free (UpdateAccountInfo, info);
1427 update_account_send_mail (UpdateAccountInfo *info)
1429 TnyTransportAccount *transport_account = NULL;
1430 ModestTnyAccountStore *account_store;
1432 account_store = modest_runtime_get_account_store ();
1434 /* We don't try to send messages while sending mails is blocked */
1435 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1438 /* Get the transport account */
1439 transport_account = (TnyTransportAccount *)
1440 modest_tny_account_store_get_server_account (account_store, info->account_name,
1441 TNY_ACCOUNT_TYPE_TRANSPORT);
1443 if (transport_account) {
1444 ModestTnySendQueue *send_queue;
1448 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1449 g_object_unref (transport_account);
1451 if (TNY_IS_SEND_QUEUE (send_queue)) {
1452 /* Get outbox folder */
1453 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1454 if (outbox) { /* this could fail in some cases */
1455 num_messages = tny_folder_get_all_count (outbox);
1456 g_object_unref (outbox);
1458 g_warning ("%s: could not get outbox", __FUNCTION__);
1462 if (num_messages != 0) {
1463 ModestMailOperation *mail_op;
1464 /* Reenable suspended items */
1465 mail_op = modest_mail_operation_new (NULL);
1466 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1468 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1471 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1479 update_account_get_msg_async_cb (TnyFolder *folder,
1485 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1486 ModestMailOperationPrivate *priv;
1488 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1491 if (TNY_IS_MSG (msg)) {
1492 TnyHeader *header = tny_msg_get_header (msg);
1495 ModestMailOperationState *state;
1496 state = modest_mail_operation_clone_state (msg_info->mail_op);
1497 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1498 state->bytes_done = msg_info->sum_total_bytes;
1499 state->bytes_total = msg_info->total_bytes;
1501 /* Notify the status change. Only notify about changes
1502 referred to bytes */
1503 g_signal_emit (G_OBJECT (msg_info->mail_op),
1504 signals[PROGRESS_CHANGED_SIGNAL],
1507 g_object_unref (header);
1508 g_slice_free (ModestMailOperationState, state);
1512 if (priv->done == priv->total) {
1513 TnyList *new_headers;
1514 UpdateAccountInfo *info;
1516 /* After getting all the messages send the ones in the
1518 info = (UpdateAccountInfo *) msg_info->user_data;
1519 update_account_send_mail (info);
1521 /* Check if the operation was a success */
1523 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1525 /* Call the user callback and free */
1526 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1527 update_account_notify_user_and_free (info, new_headers);
1528 g_object_unref (new_headers);
1530 /* Delete the helper */
1531 g_object_unref (msg_info->more_msgs);
1532 g_object_unref (msg_info->mail_op);
1533 g_slice_free (GetMsgInfo, msg_info);
1538 update_account_notify_user_and_free (UpdateAccountInfo *info,
1539 TnyList *new_headers)
1541 /* Set the account back to not busy */
1542 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1543 info->account_name, FALSE);
1547 info->callback (info->mail_op, new_headers, info->user_data);
1549 /* Mail operation end */
1550 modest_mail_operation_notify_end (info->mail_op);
1554 g_object_unref (new_headers);
1555 destroy_update_account_info (info);
1559 inbox_refreshed_cb (TnyFolder *inbox,
1564 UpdateAccountInfo *info;
1565 ModestMailOperationPrivate *priv;
1566 TnyIterator *new_headers_iter;
1567 GPtrArray *new_headers_array = NULL;
1568 gint max_size, retrieve_limit, i;
1569 ModestAccountMgr *mgr;
1570 ModestAccountRetrieveType retrieve_type;
1571 TnyList *new_headers = NULL;
1572 gboolean headers_only, ignore_limit;
1574 info = (UpdateAccountInfo *) user_data;
1575 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1576 mgr = modest_runtime_get_account_mgr ();
1578 if (canceled || err) {
1579 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1581 priv->error = g_error_copy (err);
1583 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1584 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1588 tny_folder_remove_observer (inbox, info->inbox_observer);
1589 g_object_unref (info->inbox_observer);
1590 info->inbox_observer = NULL;
1592 /* Notify the user about the error and then exit */
1593 update_account_notify_user_and_free (info, NULL);
1598 /* Try to send anyway */
1602 /* Set the last updated as the current time */
1603 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1605 /* Get the message max size */
1606 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1607 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1609 max_size = G_MAXINT;
1611 max_size = max_size * KB;
1613 /* Create the new headers array. We need it to sort the
1614 new headers by date */
1615 new_headers_array = g_ptr_array_new ();
1616 if (info->inbox_observer) {
1617 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1618 while (!tny_iterator_is_done (new_headers_iter)) {
1619 TnyHeader *header = NULL;
1621 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1622 /* Apply per-message size limits */
1623 if (tny_header_get_message_size (header) < max_size)
1624 g_ptr_array_add (new_headers_array, g_object_ref (header));
1626 g_object_unref (header);
1627 tny_iterator_next (new_headers_iter);
1629 g_object_unref (new_headers_iter);
1631 tny_folder_remove_observer (inbox, info->inbox_observer);
1632 g_object_unref (info->inbox_observer);
1633 info->inbox_observer = NULL;
1636 if (new_headers_array->len == 0) {
1637 g_ptr_array_free (new_headers_array, FALSE);
1641 /* Get per-account message amount retrieval limit */
1642 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1643 if (retrieve_limit == 0)
1644 retrieve_limit = G_MAXINT;
1646 /* Get per-account retrieval type */
1647 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1648 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1651 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1653 /* Ask the users if they want to retrieve all the messages
1654 even though the limit was exceeded */
1655 ignore_limit = FALSE;
1656 if (new_headers_array->len > retrieve_limit) {
1657 /* Ask the user if a callback has been specified and
1658 if the mail operation has a source (this means that
1659 was invoked by the user and not automatically by a
1661 if (info->retrieve_all_cb && priv->source)
1662 ignore_limit = info->retrieve_all_cb (priv->source,
1663 new_headers_array->len,
1667 /* Copy the headers to a list and free the array */
1668 new_headers = tny_simple_list_new ();
1669 for (i=0; i < new_headers_array->len; i++) {
1670 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1671 tny_list_append (new_headers, G_OBJECT (header));
1673 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1674 g_ptr_array_free (new_headers_array, FALSE);
1676 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1679 GetMsgInfo *msg_info;
1683 priv->total = tny_list_get_length (new_headers);
1685 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1687 iter = tny_list_create_iterator (new_headers);
1689 /* Create the message info */
1690 msg_info = g_slice_new0 (GetMsgInfo);
1691 msg_info->mail_op = g_object_ref (info->mail_op);
1692 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1693 msg_info->more_msgs = g_object_ref (iter);
1694 msg_info->user_data = info;
1696 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1697 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1698 TnyFolder *folder = tny_header_get_folder (header);
1700 /* Get message in an async way */
1701 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1704 g_object_unref (folder);
1707 tny_iterator_next (iter);
1709 g_object_unref (iter);
1711 /* The mail operation will finish when the last
1712 message is retrieved */
1716 /* If we don't have to retrieve the new messages then
1718 update_account_send_mail (info);
1720 /* Check if the operation was a success */
1722 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1724 /* Call the user callback and free */
1725 update_account_notify_user_and_free (info, new_headers);
1729 inbox_refresh_status_update (GObject *obj,
1733 UpdateAccountInfo *info = NULL;
1734 ModestMailOperation *self = NULL;
1735 ModestMailOperationPrivate *priv = NULL;
1736 ModestMailOperationState *state;
1738 g_return_if_fail (user_data != NULL);
1739 g_return_if_fail (status != NULL);
1741 /* Show only the status information we want */
1742 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1745 info = (UpdateAccountInfo *) user_data;
1746 self = info->mail_op;
1747 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1751 priv->done = status->position;
1752 priv->total = status->of_total;
1754 state = modest_mail_operation_clone_state (self);
1756 /* This is not a GDK lock because we are a Tinymail callback and
1757 * Tinymail already acquires the Gdk lock */
1758 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1760 g_slice_free (ModestMailOperationState, state);
1764 recurse_folders_async_cb (TnyFolderStore *folder_store,
1770 UpdateAccountInfo *info;
1771 ModestMailOperationPrivate *priv;
1773 info = (UpdateAccountInfo *) user_data;
1774 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1776 if (err || canceled) {
1777 /* If the error was previosly set by another callback
1778 don't set it again */
1780 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1782 priv->error = g_error_copy (err);
1784 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1785 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1789 /* We're not getting INBOX children if we don't want to poke all */
1790 TnyIterator *iter = tny_list_create_iterator (list);
1791 while (!tny_iterator_is_done (iter)) {
1792 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1794 /* Add to the list of all folders */
1795 tny_list_append (info->folders, (GObject *) folder);
1797 if (info->poke_all) {
1798 TnyList *folders = tny_simple_list_new ();
1799 /* Add pending call */
1800 info->pending_calls++;
1802 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1803 recurse_folders_async_cb,
1805 g_object_unref (folders);
1808 g_object_unref (G_OBJECT (folder));
1810 tny_iterator_next (iter);
1812 g_object_unref (G_OBJECT (iter));
1815 /* Remove my own pending call */
1816 info->pending_calls--;
1818 /* This means that we have all the folders */
1819 if (info->pending_calls == 0) {
1820 TnyIterator *iter_all_folders;
1821 TnyFolder *inbox = NULL;
1823 /* If there was any error do not continue */
1825 update_account_notify_user_and_free (info, NULL);
1829 iter_all_folders = tny_list_create_iterator (info->folders);
1831 /* Do a poke status over all folders */
1832 while (!tny_iterator_is_done (iter_all_folders) &&
1833 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1834 TnyFolder *folder = NULL;
1836 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1838 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1839 /* Get a reference to the INBOX */
1840 inbox = g_object_ref (folder);
1842 /* Issue a poke status over the folder */
1844 tny_folder_poke_status (folder);
1847 /* Free and go to next */
1848 g_object_unref (folder);
1849 tny_iterator_next (iter_all_folders);
1851 g_object_unref (iter_all_folders);
1853 /* Refresh the INBOX */
1855 /* Refresh the folder. Our observer receives
1856 * the new emails during folder refreshes, so
1857 * we can use observer->new_headers
1859 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1860 tny_folder_add_observer (inbox, info->inbox_observer);
1862 /* Refresh the INBOX */
1863 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1864 g_object_unref (inbox);
1866 /* We could not perform the inbox refresh but
1867 we'll try to send mails anyway */
1868 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1874 modest_mail_operation_update_account (ModestMailOperation *self,
1875 const gchar *account_name,
1877 gboolean interactive,
1878 RetrieveAllCallback retrieve_all_cb,
1879 UpdateAccountCallback callback,
1882 UpdateAccountInfo *info = NULL;
1883 ModestMailOperationPrivate *priv = NULL;
1884 ModestTnyAccountStore *account_store = NULL;
1886 ModestMailOperationState *state;
1888 /* Init mail operation */
1889 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1892 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1893 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1895 /* Get the store account */
1896 account_store = modest_runtime_get_account_store ();
1898 modest_tny_account_store_get_server_account (account_store,
1900 TNY_ACCOUNT_TYPE_STORE);
1902 /* The above function could return NULL */
1903 if (!priv->account) {
1904 /* Check if the operation was a success */
1905 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1906 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1908 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1910 /* Call the user callback */
1912 callback (self, NULL, user_data);
1914 /* Notify about operation end */
1915 modest_mail_operation_notify_end (self);
1920 /* We have once seen priv->account getting finalized during this code,
1921 * therefore adding a reference (bug #82296) */
1923 g_object_ref (priv->account);
1925 /* Create the helper object */
1926 info = g_slice_new0 (UpdateAccountInfo);
1927 info->pending_calls = 1;
1928 info->folders = tny_simple_list_new ();
1929 info->mail_op = g_object_ref (self);
1930 info->poke_all = poke_all;
1931 info->interactive = interactive;
1932 info->account_name = g_strdup (account_name);
1933 info->callback = callback;
1934 info->user_data = user_data;
1935 info->retrieve_all_cb = retrieve_all_cb;
1937 /* Set account busy */
1938 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1939 modest_mail_operation_notify_start (self);
1941 /* notify about the start of the operation */
1942 state = modest_mail_operation_clone_state (self);
1946 /* Start notifying progress */
1947 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1948 g_slice_free (ModestMailOperationState, state);
1950 /* Get all folders and continue in the callback */
1951 folders = tny_simple_list_new ();
1952 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1953 folders, NULL, FALSE,
1954 recurse_folders_async_cb,
1956 g_object_unref (folders);
1958 g_object_unref (priv->account);
1963 * Used to notify the queue from the main
1964 * loop. We call it inside an idle call to achieve that
1967 idle_notify_queue (gpointer data)
1969 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1971 gdk_threads_enter ();
1972 modest_mail_operation_notify_end (mail_op);
1973 gdk_threads_leave ();
1974 g_object_unref (mail_op);
1980 compare_headers_by_date (gconstpointer a,
1983 TnyHeader **header1, **header2;
1984 time_t sent1, sent2;
1986 header1 = (TnyHeader **) a;
1987 header2 = (TnyHeader **) b;
1989 sent1 = tny_header_get_date_sent (*header1);
1990 sent2 = tny_header_get_date_sent (*header2);
1992 /* We want the most recent ones (greater time_t) at the
2001 /* ******************************************************************* */
2002 /* ************************** STORE ACTIONS ************************* */
2003 /* ******************************************************************* */
2006 ModestMailOperation *mail_op;
2007 CreateFolderUserCallback callback;
2013 create_folder_cb (TnyFolderStore *parent_folder,
2015 TnyFolder *new_folder,
2019 ModestMailOperationPrivate *priv;
2020 CreateFolderInfo *info;
2022 info = (CreateFolderInfo *) user_data;
2023 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2025 if (canceled || err) {
2026 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2028 priv->error = g_error_copy (err);
2030 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2031 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2034 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2037 /* The user will unref the new_folder */
2039 info->callback (info->mail_op, parent_folder,
2040 new_folder, info->user_data);
2042 /* Notify about operation end */
2043 modest_mail_operation_notify_end (info->mail_op);
2046 g_object_unref (info->mail_op);
2047 g_slice_free (CreateFolderInfo, info);
2051 modest_mail_operation_create_folder (ModestMailOperation *self,
2052 TnyFolderStore *parent,
2054 CreateFolderUserCallback callback,
2057 ModestMailOperationPrivate *priv;
2059 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2060 g_return_if_fail (name);
2062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2063 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2064 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2065 g_object_ref (parent) :
2066 modest_tny_folder_get_account (TNY_FOLDER (parent));
2068 /* Check for already existing folder */
2069 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2070 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2071 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2072 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2073 _CS("ckdg_ib_folder_already_exists"));
2077 if (TNY_IS_FOLDER (parent)) {
2078 /* Check folder rules */
2079 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2080 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2081 /* Set status failed and set an error */
2082 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2083 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2084 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2085 _("mail_in_ui_folder_create_error"));
2089 if (!strcmp (name, " ") || strchr (name, '/')) {
2090 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2091 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2092 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2093 _("mail_in_ui_folder_create_error"));
2097 CreateFolderInfo *info;
2099 info = g_slice_new0 (CreateFolderInfo);
2100 info->mail_op = g_object_ref (self);
2101 info->callback = callback;
2102 info->user_data = user_data;
2104 modest_mail_operation_notify_start (self);
2106 /* Create the folder */
2107 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2110 /* Call the user callback anyway */
2112 callback (self, parent, NULL, user_data);
2113 /* Notify about operation end */
2114 modest_mail_operation_notify_end (self);
2119 modest_mail_operation_remove_folder (ModestMailOperation *self,
2121 gboolean remove_to_trash)
2123 ModestMailOperationPrivate *priv;
2124 ModestTnyFolderRules rules;
2126 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2127 g_return_if_fail (TNY_IS_FOLDER (folder));
2129 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2131 /* Check folder rules */
2132 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2133 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2134 /* Set status failed and set an error */
2135 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2136 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2137 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2138 _("mail_in_ui_folder_delete_error"));
2142 /* Get the account */
2143 priv->account = modest_tny_folder_get_account (folder);
2144 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2146 /* Delete folder or move to trash */
2147 if (remove_to_trash) {
2148 TnyFolder *trash_folder = NULL;
2149 trash_folder = modest_tny_account_get_special_folder (priv->account,
2150 TNY_FOLDER_TYPE_TRASH);
2151 /* TODO: error_handling */
2153 modest_mail_operation_notify_start (self);
2154 modest_mail_operation_xfer_folder (self, folder,
2155 TNY_FOLDER_STORE (trash_folder),
2157 g_object_unref (trash_folder);
2159 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2162 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2164 modest_mail_operation_notify_start (self);
2165 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2166 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2169 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2171 g_object_unref (parent);
2173 g_warning ("%s: could not get parent folder", __FUNCTION__);
2177 /* Notify about operation end */
2178 modest_mail_operation_notify_end (self);
2182 transfer_folder_status_cb (GObject *obj,
2186 ModestMailOperation *self;
2187 ModestMailOperationPrivate *priv;
2188 ModestMailOperationState *state;
2189 XFerFolderAsyncHelper *helper;
2191 g_return_if_fail (status != NULL);
2193 /* Show only the status information we want */
2194 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2197 helper = (XFerFolderAsyncHelper *) user_data;
2198 g_return_if_fail (helper != NULL);
2200 self = helper->mail_op;
2201 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2203 priv->done = status->position;
2204 priv->total = status->of_total;
2206 state = modest_mail_operation_clone_state (self);
2208 /* This is not a GDK lock because we are a Tinymail callback
2209 * which is already GDK locked by Tinymail */
2211 /* no gdk_threads_enter (), CHECKED */
2213 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2215 /* no gdk_threads_leave (), CHECKED */
2217 g_slice_free (ModestMailOperationState, state);
2221 transfer_folder_cb (TnyFolder *folder,
2223 TnyFolderStore *into,
2224 TnyFolder *new_folder,
2228 XFerFolderAsyncHelper *helper;
2229 ModestMailOperation *self = NULL;
2230 ModestMailOperationPrivate *priv = NULL;
2232 helper = (XFerFolderAsyncHelper *) user_data;
2233 g_return_if_fail (helper != NULL);
2235 self = helper->mail_op;
2236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2239 priv->error = g_error_copy (err);
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2242 } else if (cancelled) {
2243 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2244 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2245 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2246 _("Transference of %s was cancelled."),
2247 tny_folder_get_name (folder));
2250 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2253 /* Update state of new folder */
2255 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2256 tny_folder_poke_status (new_folder);
2259 /* Notify about operation end */
2260 modest_mail_operation_notify_end (self);
2262 /* If user defined callback function was defined, call it */
2263 if (helper->user_callback) {
2265 /* This is not a GDK lock because we are a Tinymail callback
2266 * which is already GDK locked by Tinymail */
2268 /* no gdk_threads_enter (), CHECKED */
2269 helper->user_callback (self, new_folder, helper->user_data);
2270 /* no gdk_threads_leave () , CHECKED */
2274 g_object_unref (helper->mail_op);
2275 g_slice_free (XFerFolderAsyncHelper, helper);
2280 * This function checks if the new name is a valid name for our local
2281 * folders account. The new name could not be the same than then name
2282 * of any of the mandatory local folders
2284 * We can not rely on tinymail because tinymail does not check the
2285 * name of the virtual folders that the account could have in the case
2286 * that we're doing a rename (because it directly calls Camel which
2287 * knows nothing about our virtual folders).
2289 * In the case of an actual copy/move (i.e. move/copy a folder between
2290 * accounts) tinymail uses the tny_folder_store_create_account which
2291 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2292 * checks the new name of the folder, so this call in that case
2293 * wouldn't be needed. *But* NOTE that if tinymail changes its
2294 * implementation (if folder transfers within the same account is no
2295 * longer implemented as a rename) this call will allow Modest to work
2298 * If the new name is not valid, this function will set the status to
2299 * failed and will set also an error in the mail operation
2302 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2303 TnyFolderStore *into,
2304 const gchar *new_name)
2306 if (TNY_IS_ACCOUNT (into) &&
2307 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2308 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2310 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2311 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2312 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2313 _CS("ckdg_ib_folder_already_exists"));
2320 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2322 TnyFolderStore *parent,
2323 gboolean delete_original,
2324 XferFolderAsyncUserCallback user_callback,
2327 ModestMailOperationPrivate *priv = NULL;
2328 ModestTnyFolderRules parent_rules = 0, rules;
2329 XFerFolderAsyncHelper *helper = NULL;
2330 const gchar *folder_name = NULL;
2331 const gchar *error_msg;
2333 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2334 g_return_if_fail (TNY_IS_FOLDER (folder));
2335 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2337 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2338 folder_name = tny_folder_get_name (folder);
2340 /* Set the error msg */
2341 error_msg = _("mail_in_ui_folder_move_target_error");
2343 /* Get account and set it into mail_operation */
2344 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2345 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2348 /* Get folder rules */
2349 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2350 if (TNY_IS_FOLDER (parent))
2351 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2353 /* Apply operation constraints */
2354 if ((gpointer) parent == (gpointer) folder ||
2355 (!TNY_IS_FOLDER_STORE (parent)) ||
2356 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2359 } else if (TNY_IS_FOLDER (parent) &&
2360 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2364 } else if (TNY_IS_FOLDER (parent) &&
2365 TNY_IS_FOLDER_STORE (folder) &&
2366 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2367 TNY_FOLDER_STORE (folder))) {
2368 /* Do not move a parent into a child */
2370 } else if (TNY_IS_FOLDER_STORE (parent) &&
2371 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2372 /* Check that the new folder name is not used by any
2375 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2376 /* Check that the new folder name is not used by any
2377 special local folder */
2380 /* Create the helper */
2381 helper = g_slice_new0 (XFerFolderAsyncHelper);
2382 helper->mail_op = g_object_ref (self);
2383 helper->user_callback = user_callback;
2384 helper->user_data = user_data;
2386 /* Move/Copy folder */
2387 modest_mail_operation_notify_start (self);
2388 tny_folder_copy_async (folder,
2390 tny_folder_get_name (folder),
2393 transfer_folder_status_cb,
2399 /* Set status failed and set an error */
2400 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2401 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2402 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2405 /* Call the user callback if exists */
2407 user_callback (self, NULL, user_data);
2409 /* Notify the queue */
2410 modest_mail_operation_notify_end (self);
2414 modest_mail_operation_rename_folder (ModestMailOperation *self,
2417 XferFolderAsyncUserCallback user_callback,
2420 ModestMailOperationPrivate *priv;
2421 ModestTnyFolderRules rules;
2422 XFerFolderAsyncHelper *helper;
2424 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2425 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2426 g_return_if_fail (name);
2428 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2430 /* Get account and set it into mail_operation */
2431 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2432 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2434 /* Check folder rules */
2435 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2436 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2438 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2441 TnyFolderStore *into;
2443 into = tny_folder_get_folder_store (folder);
2445 /* Check that the new folder name is not used by any
2446 special local folder */
2447 if (new_name_valid_if_local_account (priv, into, name)) {
2448 /* Create the helper */
2449 helper = g_slice_new0 (XFerFolderAsyncHelper);
2450 helper->mail_op = g_object_ref(self);
2451 helper->user_callback = user_callback;
2452 helper->user_data = user_data;
2454 /* Rename. Camel handles folder subscription/unsubscription */
2455 modest_mail_operation_notify_start (self);
2456 tny_folder_copy_async (folder, into, name, TRUE,
2458 transfer_folder_status_cb,
2460 g_object_unref (into);
2462 g_object_unref (into);
2469 /* Set status failed and set an error */
2470 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2471 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2472 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2473 _("FIXME: unable to rename"));
2476 user_callback (self, NULL, user_data);
2478 /* Notify about operation end */
2479 modest_mail_operation_notify_end (self);
2482 /* ******************************************************************* */
2483 /* ************************** MSG ACTIONS ************************* */
2484 /* ******************************************************************* */
2487 modest_mail_operation_get_msg (ModestMailOperation *self,
2489 gboolean progress_feedback,
2490 GetMsgAsyncUserCallback user_callback,
2493 GetMsgInfo *helper = NULL;
2495 ModestMailOperationPrivate *priv;
2497 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2498 g_return_if_fail (TNY_IS_HEADER (header));
2500 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2501 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2505 /* Check memory low */
2506 if (_check_memory_low (self)) {
2508 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2509 modest_mail_operation_notify_end (self);
2513 /* Get account and set it into mail_operation */
2514 folder = tny_header_get_folder (header);
2515 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2517 /* Check for cached messages */
2518 if (progress_feedback) {
2519 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2520 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2522 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2524 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2527 /* Create the helper */
2528 helper = g_slice_new0 (GetMsgInfo);
2529 helper->header = g_object_ref (header);
2530 helper->mail_op = g_object_ref (self);
2531 helper->user_callback = user_callback;
2532 helper->user_data = user_data;
2533 helper->destroy_notify = NULL;
2534 helper->last_total_bytes = 0;
2535 helper->sum_total_bytes = 0;
2536 helper->total_bytes = tny_header_get_message_size (header);
2537 helper->more_msgs = NULL;
2539 modest_mail_operation_notify_start (self);
2541 /* notify about the start of the operation */
2542 ModestMailOperationState *state;
2543 state = modest_mail_operation_clone_state (self);
2546 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2548 g_slice_free (ModestMailOperationState, state);
2550 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2552 g_object_unref (G_OBJECT (folder));
2556 get_msg_status_cb (GObject *obj,
2560 GetMsgInfo *helper = NULL;
2562 g_return_if_fail (status != NULL);
2564 /* Show only the status information we want */
2565 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2568 helper = (GetMsgInfo *) user_data;
2569 g_return_if_fail (helper != NULL);
2571 /* Notify progress */
2572 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2573 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2577 get_msg_async_cb (TnyFolder *folder,
2583 GetMsgInfo *info = NULL;
2584 ModestMailOperationPrivate *priv = NULL;
2587 info = (GetMsgInfo *) user_data;
2589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2592 if (info->more_msgs) {
2593 tny_iterator_next (info->more_msgs);
2594 finished = (tny_iterator_is_done (info->more_msgs));
2596 finished = (priv->done == priv->total) ? TRUE : FALSE;
2599 /* If canceled by the user, ignore the error given by Tinymail */
2603 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2605 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2606 priv->error = g_error_copy ((const GError *) err);
2608 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2610 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2611 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2614 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2615 /* Set the success status before calling the user callback */
2616 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2620 /* Call the user callback */
2621 if (info->user_callback)
2622 info->user_callback (info->mail_op, info->header, canceled,
2623 msg, err, info->user_data);
2625 /* Notify about operation end if this is the last callback */
2627 /* Free user data */
2628 if (info->destroy_notify)
2629 info->destroy_notify (info->user_data);
2631 /* Notify about operation end */
2632 modest_mail_operation_notify_end (info->mail_op);
2635 if (info->more_msgs)
2636 g_object_unref (info->more_msgs);
2637 g_object_unref (info->header);
2638 g_object_unref (info->mail_op);
2639 g_slice_free (GetMsgInfo, info);
2640 } else if (info->more_msgs) {
2641 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2642 TnyFolder *folder = tny_header_get_folder (header);
2644 g_object_unref (info->header);
2645 info->header = g_object_ref (header);
2647 /* Retrieve the next message */
2648 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2650 g_object_unref (header);
2651 g_object_unref (folder);
2653 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2658 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2659 TnyList *header_list,
2660 GetMsgAsyncUserCallback user_callback,
2662 GDestroyNotify notify)
2664 ModestMailOperationPrivate *priv = NULL;
2666 TnyIterator *iter = NULL;
2667 gboolean has_uncached_messages;
2669 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2671 /* Init mail operation */
2672 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2673 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2675 priv->total = tny_list_get_length(header_list);
2677 /* Check memory low */
2678 if (_check_memory_low (self)) {
2679 if (user_callback) {
2680 TnyHeader *header = NULL;
2683 if (tny_list_get_length (header_list) > 0) {
2684 iter = tny_list_create_iterator (header_list);
2685 header = (TnyHeader *) tny_iterator_get_current (iter);
2686 g_object_unref (iter);
2688 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2690 g_object_unref (header);
2694 /* Notify about operation end */
2695 modest_mail_operation_notify_end (self);
2699 /* Check uncached messages */
2700 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2701 !has_uncached_messages && !tny_iterator_is_done (iter);
2702 tny_iterator_next (iter)) {
2705 header = (TnyHeader *) tny_iterator_get_current (iter);
2706 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2707 has_uncached_messages = TRUE;
2708 g_object_unref (header);
2710 g_object_unref (iter);
2711 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2713 /* Get account and set it into mail_operation */
2714 if (tny_list_get_length (header_list) >= 1) {
2715 TnyIterator *iterator = tny_list_create_iterator (header_list);
2716 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2718 TnyFolder *folder = tny_header_get_folder (header);
2720 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2721 g_object_unref (folder);
2723 g_object_unref (header);
2725 g_object_unref (iterator);
2728 msg_list_size = compute_message_list_size (header_list, 0);
2730 modest_mail_operation_notify_start (self);
2731 iter = tny_list_create_iterator (header_list);
2732 if (!tny_iterator_is_done (iter)) {
2733 /* notify about the start of the operation */
2734 ModestMailOperationState *state;
2735 state = modest_mail_operation_clone_state (self);
2738 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2741 GetMsgInfo *msg_info = NULL;
2742 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2743 TnyFolder *folder = tny_header_get_folder (header);
2745 /* Create the message info */
2746 msg_info = g_slice_new0 (GetMsgInfo);
2747 msg_info->mail_op = g_object_ref (self);
2748 msg_info->header = g_object_ref (header);
2749 msg_info->more_msgs = g_object_ref (iter);
2750 msg_info->user_callback = user_callback;
2751 msg_info->user_data = user_data;
2752 msg_info->destroy_notify = notify;
2753 msg_info->last_total_bytes = 0;
2754 msg_info->sum_total_bytes = 0;
2755 msg_info->total_bytes = msg_list_size;
2757 /* The callback will call it per each header */
2758 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2760 /* Free and go on */
2761 g_object_unref (header);
2762 g_object_unref (folder);
2763 g_slice_free (ModestMailOperationState, state);
2765 g_object_unref (iter);
2770 remove_msgs_async_cb (TnyFolder *folder,
2775 gboolean expunge, leave_on_server;
2776 const gchar *account_name;
2777 TnyAccount *account;
2778 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2779 ModestMailOperation *self;
2780 ModestMailOperationPrivate *priv;
2781 ModestProtocolRegistry *protocol_registry;
2783 self = (ModestMailOperation *) user_data;
2784 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2785 protocol_registry = modest_runtime_get_protocol_registry ();
2787 if (canceled || err) {
2788 /* If canceled by the user, ignore the error given by Tinymail */
2790 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2792 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2793 priv->error = g_error_copy ((const GError *) err);
2794 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2797 modest_mail_operation_notify_end (self);
2798 g_object_unref (self);
2802 account = modest_tny_folder_get_account (folder);
2803 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2805 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2807 account_proto = modest_tny_account_get_protocol_type (account);
2808 g_object_unref (account);
2810 if ((modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) &&
2811 !leave_on_server) ||
2812 !modest_tny_folder_is_remote_folder (folder))
2818 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2823 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2825 gboolean remove_to_trash /*ignored*/)
2827 TnyFolder *folder = NULL;
2828 ModestMailOperationPrivate *priv;
2829 TnyIterator *iter = NULL;
2830 TnyHeader *header = NULL;
2831 TnyList *remove_headers = NULL;
2832 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2833 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2835 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2836 g_return_if_fail (TNY_IS_LIST (headers));
2838 if (remove_to_trash)
2839 g_warning ("remove to trash is not implemented");
2841 if (tny_list_get_length(headers) == 0) {
2842 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2843 goto cleanup; /* nothing to do */
2846 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2848 /* Get folder from first header and sync it */
2849 iter = tny_list_create_iterator (headers);
2850 header = TNY_HEADER (tny_iterator_get_current (iter));
2851 g_object_unref (iter);
2853 folder = tny_header_get_folder (header);
2854 if (!TNY_IS_FOLDER(folder)) {
2855 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2859 /* Use the merged folder if we're removing messages from outbox */
2860 if (modest_tny_folder_is_local_folder (folder)) {
2861 ModestTnyLocalFoldersAccount *local_account;
2863 local_account = (ModestTnyLocalFoldersAccount *)
2864 modest_tny_account_store_get_local_folders_account (accstore);
2865 g_object_unref (folder);
2866 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
2867 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2868 g_object_unref (local_account);
2871 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2872 TnyIterator *headers_iter = tny_list_create_iterator (headers);
2874 while (!tny_iterator_is_done (headers_iter)) {
2875 TnyTransportAccount *traccount = NULL;
2876 TnyHeader *hdr = NULL;
2878 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
2879 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
2882 ModestTnySendQueueStatus status;
2883 ModestTnySendQueue *send_queue;
2885 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2886 if (TNY_IS_SEND_QUEUE (send_queue)) {
2889 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2890 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2891 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2892 if (G_UNLIKELY (remove_headers == NULL))
2893 remove_headers = tny_simple_list_new ();
2894 tny_list_append(remove_headers, G_OBJECT(hdr));
2898 g_object_unref(traccount);
2900 g_object_unref(hdr);
2901 tny_iterator_next (headers_iter);
2903 g_object_unref(headers_iter);
2906 /* Get account and set it into mail_operation */
2907 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2908 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2909 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2911 if (!remove_headers)
2912 remove_headers = g_object_ref (headers);
2914 /* remove message from folder */
2915 modest_mail_operation_notify_start (self);
2916 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2917 NULL, g_object_ref (self));
2921 g_object_unref (remove_headers);
2923 g_object_unref (header);
2925 g_object_unref (folder);
2929 notify_progress_of_multiple_messages (ModestMailOperation *self,
2931 gint *last_total_bytes,
2932 gint *sum_total_bytes,
2934 gboolean increment_done)
2936 ModestMailOperationPrivate *priv;
2937 ModestMailOperationState *state;
2938 gboolean is_num_bytes = FALSE;
2940 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2942 /* We know that tinymail sends us information about
2943 * transferred bytes with this particular message
2945 if (status->message)
2946 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2948 state = modest_mail_operation_clone_state (self);
2949 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2950 /* We know that we're in a different message when the
2951 total number of bytes to transfer is different. Of
2952 course it could fail if we're transferring messages
2953 of the same size, but this is a workarround */
2954 if (status->of_total != *last_total_bytes) {
2955 /* We need to increment the done when there is
2956 no information about each individual
2957 message, we need to do this in message
2958 transfers, and we don't do it for getting
2962 *sum_total_bytes += *last_total_bytes;
2963 *last_total_bytes = status->of_total;
2965 state->bytes_done += status->position + *sum_total_bytes;
2966 state->bytes_total = total_bytes;
2968 /* Notify the status change. Only notify about changes
2969 referred to bytes */
2970 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2974 g_slice_free (ModestMailOperationState, state);
2978 transfer_msgs_status_cb (GObject *obj,
2982 XFerMsgsAsyncHelper *helper;
2984 g_return_if_fail (status != NULL);
2986 /* Show only the status information we want */
2987 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2990 helper = (XFerMsgsAsyncHelper *) user_data;
2991 g_return_if_fail (helper != NULL);
2993 /* Notify progress */
2994 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2995 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2999 transfer_msgs_sync_folder_cb (TnyFolder *self,
3004 XFerMsgsAsyncHelper *helper;
3005 /* We don't care here about the results of the
3007 helper = (XFerMsgsAsyncHelper *) user_data;
3009 /* Notify about operation end */
3010 modest_mail_operation_notify_end (helper->mail_op);
3012 /* If user defined callback function was defined, call it */
3013 if (helper->user_callback)
3014 helper->user_callback (helper->mail_op, helper->user_data);
3017 if (helper->more_msgs)
3018 g_object_unref (helper->more_msgs);
3019 if (helper->headers)
3020 g_object_unref (helper->headers);
3021 if (helper->dest_folder)
3022 g_object_unref (helper->dest_folder);
3023 if (helper->mail_op)
3024 g_object_unref (helper->mail_op);
3025 g_slice_free (XFerMsgsAsyncHelper, helper);
3029 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3031 XFerMsgsAsyncHelper *helper;
3032 ModestMailOperation *self;
3033 ModestMailOperationPrivate *priv;
3034 gboolean finished = TRUE;
3036 helper = (XFerMsgsAsyncHelper *) user_data;
3037 self = helper->mail_op;
3039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3042 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3044 priv->error = g_error_copy (err);
3046 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3047 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3048 if (helper->more_msgs) {
3049 /* We'll transfer the next message in the list */
3050 tny_iterator_next (helper->more_msgs);
3051 if (!tny_iterator_is_done (helper->more_msgs)) {
3052 GObject *next_header;
3053 g_object_unref (helper->headers);
3054 helper->headers = tny_simple_list_new ();
3055 next_header = tny_iterator_get_current (helper->more_msgs);
3056 tny_list_append (helper->headers, next_header);
3057 g_object_unref (next_header);
3063 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3068 /* Synchronize the source folder contents. This should
3069 be done by tinymail but the camel_folder_sync it's
3070 actually disabled in transfer_msgs_thread_clean
3071 because it's supposed to cause hangs */
3072 tny_folder_sync_async (folder, helper->delete,
3073 transfer_msgs_sync_folder_cb,
3076 /* Transfer more messages */
3077 tny_folder_transfer_msgs_async (folder,
3079 helper->dest_folder,
3082 transfer_msgs_status_cb,
3087 /* Computes the size of the messages the headers in the list belongs
3088 to. If num_elements is different from 0 then it only takes into
3089 account the first num_elements for the calculation */
3091 compute_message_list_size (TnyList *headers,
3095 guint size = 0, element = 0;
3097 /* If num_elements is not valid then take all into account */
3098 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3099 num_elements = tny_list_get_length (headers);
3101 iter = tny_list_create_iterator (headers);
3102 while (!tny_iterator_is_done (iter) && element < num_elements) {
3103 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3104 size += tny_header_get_message_size (header);
3105 g_object_unref (header);
3106 tny_iterator_next (iter);
3109 g_object_unref (iter);
3115 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3118 gboolean delete_original,
3119 XferMsgsAsyncUserCallback user_callback,
3122 ModestMailOperationPrivate *priv = NULL;
3123 TnyIterator *iter = NULL;
3124 TnyFolder *src_folder = NULL;
3125 XFerMsgsAsyncHelper *helper = NULL;
3126 TnyHeader *header = NULL;
3127 ModestTnyFolderRules rules = 0;
3128 TnyAccount *dst_account = NULL;
3129 gboolean leave_on_server;
3130 ModestMailOperationState *state;
3131 ModestProtocolRegistry *protocol_registry;
3132 ModestProtocolType account_protocol;
3134 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3135 g_return_if_fail (headers && TNY_IS_LIST (headers));
3136 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3138 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3139 protocol_registry = modest_runtime_get_protocol_registry ();
3141 priv->total = tny_list_get_length (headers);
3143 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3144 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3146 /* Apply folder rules */
3147 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3148 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3149 /* Set status failed and set an error */
3150 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3151 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3152 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3153 _CS("ckct_ib_unable_to_paste_here"));
3154 /* Notify the queue */
3155 modest_mail_operation_notify_end (self);
3159 /* Get source folder */
3160 iter = tny_list_create_iterator (headers);
3161 header = TNY_HEADER (tny_iterator_get_current (iter));
3163 src_folder = tny_header_get_folder (header);
3164 g_object_unref (header);
3166 g_object_unref (iter);
3168 if (src_folder == NULL) {
3169 /* Notify the queue */
3170 modest_mail_operation_notify_end (self);
3172 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3177 /* Check folder source and destination */
3178 if (src_folder == folder) {
3179 /* Set status failed and set an error */
3180 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3181 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3182 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3183 _("mail_in_ui_folder_copy_target_error"));
3185 /* Notify the queue */
3186 modest_mail_operation_notify_end (self);
3189 g_object_unref (src_folder);
3193 /* Create the helper */
3194 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3195 helper->mail_op = g_object_ref(self);
3196 helper->dest_folder = g_object_ref(folder);
3197 helper->user_callback = user_callback;
3198 helper->user_data = user_data;
3199 helper->last_total_bytes = 0;
3200 helper->sum_total_bytes = 0;
3201 helper->total_bytes = compute_message_list_size (headers, 0);
3203 /* Get account and set it into mail_operation */
3204 priv->account = modest_tny_folder_get_account (src_folder);
3205 dst_account = modest_tny_folder_get_account (folder);
3207 if (priv->account == dst_account) {
3208 /* Transfer all messages at once using the fast
3209 * method. Note that depending on the server this
3210 * might not be that fast, and might not be
3211 * user-cancellable either */
3212 helper->headers = g_object_ref (headers);
3213 helper->more_msgs = NULL;
3215 /* Transfer messages one by one so the user can cancel
3218 helper->headers = tny_simple_list_new ();
3219 helper->more_msgs = tny_list_create_iterator (headers);
3220 hdr = tny_iterator_get_current (helper->more_msgs);
3221 tny_list_append (helper->headers, hdr);
3222 g_object_unref (hdr);
3225 /* If leave_on_server is set to TRUE then don't use
3226 delete_original, we always pass FALSE. This is because
3227 otherwise tinymail will try to sync the source folder and
3228 this could cause an error if we're offline while
3229 transferring an already downloaded message from a POP
3231 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3232 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3233 const gchar *account_name;
3235 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3236 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3239 leave_on_server = FALSE;
3242 /* Do not delete messages if leave on server is TRUE */
3243 helper->delete = (leave_on_server) ? FALSE : delete_original;
3245 modest_mail_operation_notify_start (self);
3247 /* Start notifying progress */
3248 state = modest_mail_operation_clone_state (self);
3251 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3252 g_slice_free (ModestMailOperationState, state);
3254 tny_folder_transfer_msgs_async (src_folder,
3259 transfer_msgs_status_cb,
3261 g_object_unref (src_folder);
3262 g_object_unref (dst_account);
3267 on_refresh_folder (TnyFolder *folder,
3272 RefreshAsyncHelper *helper = NULL;
3273 ModestMailOperation *self = NULL;
3274 ModestMailOperationPrivate *priv = NULL;
3276 helper = (RefreshAsyncHelper *) user_data;
3277 self = helper->mail_op;
3278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3280 g_return_if_fail(priv!=NULL);
3283 priv->error = g_error_copy (error);
3284 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3289 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3290 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3291 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3292 _("Error trying to refresh the contents of %s"),
3293 tny_folder_get_name (folder));
3297 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3300 /* Call user defined callback, if it exists */
3301 if (helper->user_callback) {
3303 /* This is not a GDK lock because we are a Tinymail callback and
3304 * Tinymail already acquires the Gdk lock */
3305 helper->user_callback (self, folder, helper->user_data);
3309 g_slice_free (RefreshAsyncHelper, helper);
3311 /* Notify about operation end */
3312 modest_mail_operation_notify_end (self);
3313 g_object_unref(self);
3317 on_refresh_folder_status_update (GObject *obj,
3321 RefreshAsyncHelper *helper = NULL;
3322 ModestMailOperation *self = NULL;
3323 ModestMailOperationPrivate *priv = NULL;
3324 ModestMailOperationState *state;
3326 g_return_if_fail (user_data != NULL);
3327 g_return_if_fail (status != NULL);
3329 /* Show only the status information we want */
3330 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3333 helper = (RefreshAsyncHelper *) user_data;
3334 self = helper->mail_op;
3335 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3337 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3339 priv->done = status->position;
3340 priv->total = status->of_total;
3342 state = modest_mail_operation_clone_state (self);
3344 /* This is not a GDK lock because we are a Tinymail callback and
3345 * Tinymail already acquires the Gdk lock */
3346 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3348 g_slice_free (ModestMailOperationState, state);
3352 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3354 RefreshAsyncUserCallback user_callback,
3357 ModestMailOperationPrivate *priv = NULL;
3358 RefreshAsyncHelper *helper = NULL;
3360 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3362 /* Check memory low */
3363 if (_check_memory_low (self)) {
3365 user_callback (self, folder, user_data);
3366 /* Notify about operation end */
3367 modest_mail_operation_notify_end (self);
3371 /* Get account and set it into mail_operation */
3372 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3373 priv->account = modest_tny_folder_get_account (folder);
3374 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3376 /* Create the helper */
3377 helper = g_slice_new0 (RefreshAsyncHelper);
3378 helper->mail_op = g_object_ref(self);
3379 helper->user_callback = user_callback;
3380 helper->user_data = user_data;
3382 modest_mail_operation_notify_start (self);
3384 /* notify that the operation was started */
3385 ModestMailOperationState *state;
3386 state = modest_mail_operation_clone_state (self);
3389 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3391 g_slice_free (ModestMailOperationState, state);
3393 tny_folder_refresh_async (folder,
3395 on_refresh_folder_status_update,
3400 run_queue_notify_and_destroy (RunQueueHelper *helper,
3401 ModestMailOperationStatus status)
3403 ModestMailOperationPrivate *priv;
3406 if (helper->error_handler &&
3407 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3408 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3409 if (helper->start_handler &&
3410 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3411 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3412 if (helper->stop_handler &&
3413 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3414 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3418 priv->status = status;
3421 modest_mail_operation_notify_end (helper->self);
3424 g_object_unref (helper->queue);
3425 g_object_unref (helper->self);
3426 g_slice_free (RunQueueHelper, helper);
3430 run_queue_stop (ModestTnySendQueue *queue,
3433 RunQueueHelper *helper;
3435 g_debug ("%s sending queue stopped", __FUNCTION__);
3437 helper = (RunQueueHelper *) user_data;
3438 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3442 modest_mail_operation_run_queue (ModestMailOperation *self,
3443 ModestTnySendQueue *queue)
3445 ModestMailOperationPrivate *priv;
3446 RunQueueHelper *helper;
3448 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3449 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3450 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3452 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3453 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3454 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3456 /* Create the helper */
3457 helper = g_slice_new0 (RunQueueHelper);
3458 helper->queue = g_object_ref (queue);
3459 helper->self = g_object_ref (self);
3460 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3461 G_CALLBACK (run_queue_stop),
3464 /* Notify operation has started */
3465 modest_mail_operation_notify_start (self);
3466 g_debug ("%s, run queue started", __FUNCTION__);
3470 queue_wakeup_callback (ModestTnySendQueue *queue,
3475 ModestMailOperation *mail_op;
3476 ModestMailOperationPrivate *priv;
3478 mail_op = (ModestMailOperation *) userdata;
3479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3481 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3482 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3485 modest_mail_operation_notify_end (mail_op);
3486 g_object_unref (mail_op);
3490 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3491 ModestTnySendQueue *queue)
3493 ModestMailOperationPrivate *priv;
3495 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3496 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3499 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3500 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3501 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3503 g_object_ref (self);
3505 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3506 modest_mail_operation_notify_start (self);
3510 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3512 ModestMailOperation *self = (ModestMailOperation *) userdata;
3513 ModestMailOperationPrivate *priv;
3515 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3516 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3517 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3519 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3521 modest_mail_operation_notify_end (self);
3522 g_object_unref (self);
3526 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3528 ModestMailOperationPrivate *priv;
3530 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3531 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3534 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3536 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3537 priv->account = NULL;
3538 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3540 modest_mail_operation_notify_start (self);
3541 g_object_ref (self);
3542 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3546 sync_folder_finish_callback (TnyFolder *self,
3552 ModestMailOperation *mail_op;
3553 ModestMailOperationPrivate *priv;
3555 mail_op = (ModestMailOperation *) user_data;
3556 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3558 /* If canceled by the user, ignore the error given by Tinymail */
3560 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3562 /* If the operation was a sync then the status is
3563 failed, but if it's part of another operation then
3564 just set it as finished with errors */
3565 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3566 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3568 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3569 priv->error = g_error_copy ((const GError *) err);
3570 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3572 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3575 modest_mail_operation_notify_end (mail_op);
3576 g_object_unref (mail_op);
3580 modest_mail_operation_sync_folder (ModestMailOperation *self,
3581 TnyFolder *folder, gboolean expunge)
3583 ModestMailOperationPrivate *priv;
3585 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3586 g_return_if_fail (TNY_IS_FOLDER (folder));
3587 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3589 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3590 priv->account = modest_tny_folder_get_account (folder);
3591 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3593 modest_mail_operation_notify_start (self);
3594 g_object_ref (self);
3595 tny_folder_sync_async (folder, expunge,
3596 (TnyFolderCallback) sync_folder_finish_callback,
3601 modest_mail_operation_notify_start (ModestMailOperation *self)
3603 ModestMailOperationPrivate *priv = NULL;
3605 g_return_if_fail (self);
3607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3609 /* Ensure that all the fields are filled correctly */
3610 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3612 /* Notify the observers about the mail operation. We do not
3613 wrapp this emission because we assume that this function is
3614 always called from within the main lock */
3615 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3620 * It's used by the mail operation queue to notify the observers
3621 * attached to that signal that the operation finished. We need to use
3622 * that because tinymail does not give us the progress of a given
3623 * operation when it finishes (it directly calls the operation
3627 modest_mail_operation_notify_end (ModestMailOperation *self)
3629 ModestMailOperationPrivate *priv = NULL;
3631 g_return_if_fail (self);
3633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3635 /* Notify the observers about the mail operation end. We do
3636 not wrapp this emission because we assume that this
3637 function is always called from within the main lock */
3638 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3640 /* Remove the error user data */
3641 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3642 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3646 modest_mail_operation_get_account (ModestMailOperation *self)
3648 ModestMailOperationPrivate *priv = NULL;
3650 g_return_val_if_fail (self, NULL);
3652 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3654 return (priv->account) ? g_object_ref (priv->account) : NULL;
3658 modest_mail_operation_noop (ModestMailOperation *self)
3660 ModestMailOperationPrivate *priv = NULL;
3662 g_return_if_fail (self);
3664 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3665 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3666 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3670 /* This mail operation does nothing actually */
3671 modest_mail_operation_notify_start (self);
3672 modest_mail_operation_notify_end (self);
3677 modest_mail_operation_to_string (ModestMailOperation *self)
3679 const gchar *type, *status, *account_id;
3680 ModestMailOperationPrivate *priv = NULL;
3682 g_return_val_if_fail (self, NULL);
3684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3686 /* new operations don't have anything interesting */
3687 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3688 return g_strdup_printf ("%p <new operation>", self);
3690 switch (priv->op_type) {
3691 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3692 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3693 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3694 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3695 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3696 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3697 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3698 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3699 default: type = "UNEXPECTED"; break;
3702 switch (priv->status) {
3703 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3704 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3705 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3706 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3707 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3708 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3709 default: status= "UNEXPECTED"; break;
3712 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3714 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3715 priv->done, priv->total,
3716 priv->error && priv->error->message ? priv->error->message : "");
3720 * Once the mail operations were objects this will be no longer
3721 * needed. I don't like it, but we need it for the moment
3724 _check_memory_low (ModestMailOperation *mail_op)
3726 if (modest_platform_check_memory_low (NULL, FALSE)) {
3727 ModestMailOperationPrivate *priv;
3729 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3730 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3731 g_set_error (&(priv->error),
3732 MODEST_MAIL_OPERATION_ERROR,
3733 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3734 "Not enough memory to complete the operation");