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 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2866 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2867 g_object_unref (folder);
2868 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
2870 g_object_unref (local_account);
2873 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2874 TnyIterator *headers_iter = tny_list_create_iterator (headers);
2876 while (!tny_iterator_is_done (headers_iter)) {
2877 TnyTransportAccount *traccount = NULL;
2878 TnyHeader *hdr = NULL;
2880 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
2881 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
2884 ModestTnySendQueueStatus status;
2885 ModestTnySendQueue *send_queue;
2887 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2888 if (TNY_IS_SEND_QUEUE (send_queue)) {
2891 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2892 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2893 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2894 if (G_UNLIKELY (remove_headers == NULL))
2895 remove_headers = tny_simple_list_new ();
2896 tny_list_append(remove_headers, G_OBJECT(hdr));
2900 g_object_unref(traccount);
2902 g_object_unref(hdr);
2903 tny_iterator_next (headers_iter);
2905 g_object_unref(headers_iter);
2908 /* Get account and set it into mail_operation */
2909 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2910 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2911 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2913 if (!remove_headers)
2914 remove_headers = g_object_ref (headers);
2916 /* remove message from folder */
2917 modest_mail_operation_notify_start (self);
2918 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2919 NULL, g_object_ref (self));
2923 g_object_unref (remove_headers);
2925 g_object_unref (header);
2927 g_object_unref (folder);
2931 notify_progress_of_multiple_messages (ModestMailOperation *self,
2933 gint *last_total_bytes,
2934 gint *sum_total_bytes,
2936 gboolean increment_done)
2938 ModestMailOperationPrivate *priv;
2939 ModestMailOperationState *state;
2940 gboolean is_num_bytes = FALSE;
2942 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2944 /* We know that tinymail sends us information about
2945 * transferred bytes with this particular message
2947 if (status->message)
2948 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2950 state = modest_mail_operation_clone_state (self);
2951 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2952 /* We know that we're in a different message when the
2953 total number of bytes to transfer is different. Of
2954 course it could fail if we're transferring messages
2955 of the same size, but this is a workarround */
2956 if (status->of_total != *last_total_bytes) {
2957 /* We need to increment the done when there is
2958 no information about each individual
2959 message, we need to do this in message
2960 transfers, and we don't do it for getting
2964 *sum_total_bytes += *last_total_bytes;
2965 *last_total_bytes = status->of_total;
2967 state->bytes_done += status->position + *sum_total_bytes;
2968 state->bytes_total = total_bytes;
2970 /* Notify the status change. Only notify about changes
2971 referred to bytes */
2972 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2976 g_slice_free (ModestMailOperationState, state);
2980 transfer_msgs_status_cb (GObject *obj,
2984 XFerMsgsAsyncHelper *helper;
2986 g_return_if_fail (status != NULL);
2988 /* Show only the status information we want */
2989 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2992 helper = (XFerMsgsAsyncHelper *) user_data;
2993 g_return_if_fail (helper != NULL);
2995 /* Notify progress */
2996 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2997 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3001 transfer_msgs_sync_folder_cb (TnyFolder *self,
3006 XFerMsgsAsyncHelper *helper;
3007 /* We don't care here about the results of the
3009 helper = (XFerMsgsAsyncHelper *) user_data;
3011 /* Notify about operation end */
3012 modest_mail_operation_notify_end (helper->mail_op);
3014 /* If user defined callback function was defined, call it */
3015 if (helper->user_callback)
3016 helper->user_callback (helper->mail_op, helper->user_data);
3019 if (helper->more_msgs)
3020 g_object_unref (helper->more_msgs);
3021 if (helper->headers)
3022 g_object_unref (helper->headers);
3023 if (helper->dest_folder)
3024 g_object_unref (helper->dest_folder);
3025 if (helper->mail_op)
3026 g_object_unref (helper->mail_op);
3027 g_slice_free (XFerMsgsAsyncHelper, helper);
3031 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3033 XFerMsgsAsyncHelper *helper;
3034 ModestMailOperation *self;
3035 ModestMailOperationPrivate *priv;
3036 gboolean finished = TRUE;
3038 helper = (XFerMsgsAsyncHelper *) user_data;
3039 self = helper->mail_op;
3041 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3044 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3046 priv->error = g_error_copy (err);
3048 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3049 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3050 if (helper->more_msgs) {
3051 /* We'll transfer the next message in the list */
3052 tny_iterator_next (helper->more_msgs);
3053 if (!tny_iterator_is_done (helper->more_msgs)) {
3054 GObject *next_header;
3055 g_object_unref (helper->headers);
3056 helper->headers = tny_simple_list_new ();
3057 next_header = tny_iterator_get_current (helper->more_msgs);
3058 tny_list_append (helper->headers, next_header);
3059 g_object_unref (next_header);
3065 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3070 /* Synchronize the source folder contents. This should
3071 be done by tinymail but the camel_folder_sync it's
3072 actually disabled in transfer_msgs_thread_clean
3073 because it's supposed to cause hangs */
3074 tny_folder_sync_async (folder, helper->delete,
3075 transfer_msgs_sync_folder_cb,
3078 /* Transfer more messages */
3079 tny_folder_transfer_msgs_async (folder,
3081 helper->dest_folder,
3084 transfer_msgs_status_cb,
3089 /* Computes the size of the messages the headers in the list belongs
3090 to. If num_elements is different from 0 then it only takes into
3091 account the first num_elements for the calculation */
3093 compute_message_list_size (TnyList *headers,
3097 guint size = 0, element = 0;
3099 /* If num_elements is not valid then take all into account */
3100 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3101 num_elements = tny_list_get_length (headers);
3103 iter = tny_list_create_iterator (headers);
3104 while (!tny_iterator_is_done (iter) && element < num_elements) {
3105 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3106 size += tny_header_get_message_size (header);
3107 g_object_unref (header);
3108 tny_iterator_next (iter);
3111 g_object_unref (iter);
3117 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3120 gboolean delete_original,
3121 XferMsgsAsyncUserCallback user_callback,
3124 ModestMailOperationPrivate *priv = NULL;
3125 TnyIterator *iter = NULL;
3126 TnyFolder *src_folder = NULL;
3127 XFerMsgsAsyncHelper *helper = NULL;
3128 TnyHeader *header = NULL;
3129 ModestTnyFolderRules rules = 0;
3130 TnyAccount *dst_account = NULL;
3131 gboolean leave_on_server;
3132 ModestMailOperationState *state;
3133 ModestProtocolRegistry *protocol_registry;
3134 ModestProtocolType account_protocol;
3136 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3137 g_return_if_fail (headers && TNY_IS_LIST (headers));
3138 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3140 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3141 protocol_registry = modest_runtime_get_protocol_registry ();
3143 priv->total = tny_list_get_length (headers);
3145 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3146 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3148 /* Apply folder rules */
3149 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3150 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3151 /* Set status failed and set an error */
3152 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3153 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3154 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3155 _CS("ckct_ib_unable_to_paste_here"));
3156 /* Notify the queue */
3157 modest_mail_operation_notify_end (self);
3161 /* Get source folder */
3162 iter = tny_list_create_iterator (headers);
3163 header = TNY_HEADER (tny_iterator_get_current (iter));
3165 src_folder = tny_header_get_folder (header);
3166 g_object_unref (header);
3168 g_object_unref (iter);
3170 if (src_folder == NULL) {
3171 /* Notify the queue */
3172 modest_mail_operation_notify_end (self);
3174 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3179 /* Check folder source and destination */
3180 if (src_folder == folder) {
3181 /* Set status failed and set an error */
3182 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3183 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3184 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3185 _("mail_in_ui_folder_copy_target_error"));
3187 /* Notify the queue */
3188 modest_mail_operation_notify_end (self);
3191 g_object_unref (src_folder);
3195 /* Create the helper */
3196 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3197 helper->mail_op = g_object_ref(self);
3198 helper->dest_folder = g_object_ref(folder);
3199 helper->user_callback = user_callback;
3200 helper->user_data = user_data;
3201 helper->last_total_bytes = 0;
3202 helper->sum_total_bytes = 0;
3203 helper->total_bytes = compute_message_list_size (headers, 0);
3205 /* Get account and set it into mail_operation */
3206 priv->account = modest_tny_folder_get_account (src_folder);
3207 dst_account = modest_tny_folder_get_account (folder);
3209 if (priv->account == dst_account) {
3210 /* Transfer all messages at once using the fast
3211 * method. Note that depending on the server this
3212 * might not be that fast, and might not be
3213 * user-cancellable either */
3214 helper->headers = g_object_ref (headers);
3215 helper->more_msgs = NULL;
3217 /* Transfer messages one by one so the user can cancel
3220 helper->headers = tny_simple_list_new ();
3221 helper->more_msgs = tny_list_create_iterator (headers);
3222 hdr = tny_iterator_get_current (helper->more_msgs);
3223 tny_list_append (helper->headers, hdr);
3224 g_object_unref (hdr);
3227 /* If leave_on_server is set to TRUE then don't use
3228 delete_original, we always pass FALSE. This is because
3229 otherwise tinymail will try to sync the source folder and
3230 this could cause an error if we're offline while
3231 transferring an already downloaded message from a POP
3233 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3234 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3235 const gchar *account_name;
3237 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3238 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3241 leave_on_server = FALSE;
3244 /* Do not delete messages if leave on server is TRUE */
3245 helper->delete = (leave_on_server) ? FALSE : delete_original;
3247 modest_mail_operation_notify_start (self);
3249 /* Start notifying progress */
3250 state = modest_mail_operation_clone_state (self);
3253 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3254 g_slice_free (ModestMailOperationState, state);
3256 tny_folder_transfer_msgs_async (src_folder,
3261 transfer_msgs_status_cb,
3263 g_object_unref (src_folder);
3264 g_object_unref (dst_account);
3269 on_refresh_folder (TnyFolder *folder,
3274 RefreshAsyncHelper *helper = NULL;
3275 ModestMailOperation *self = NULL;
3276 ModestMailOperationPrivate *priv = NULL;
3278 helper = (RefreshAsyncHelper *) user_data;
3279 self = helper->mail_op;
3280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3282 g_return_if_fail(priv!=NULL);
3285 priv->error = g_error_copy (error);
3286 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3291 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3292 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3293 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3294 _("Error trying to refresh the contents of %s"),
3295 tny_folder_get_name (folder));
3299 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3302 /* Call user defined callback, if it exists */
3303 if (helper->user_callback) {
3305 /* This is not a GDK lock because we are a Tinymail callback and
3306 * Tinymail already acquires the Gdk lock */
3307 helper->user_callback (self, folder, helper->user_data);
3311 g_slice_free (RefreshAsyncHelper, helper);
3313 /* Notify about operation end */
3314 modest_mail_operation_notify_end (self);
3315 g_object_unref(self);
3319 on_refresh_folder_status_update (GObject *obj,
3323 RefreshAsyncHelper *helper = NULL;
3324 ModestMailOperation *self = NULL;
3325 ModestMailOperationPrivate *priv = NULL;
3326 ModestMailOperationState *state;
3328 g_return_if_fail (user_data != NULL);
3329 g_return_if_fail (status != NULL);
3331 /* Show only the status information we want */
3332 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3335 helper = (RefreshAsyncHelper *) user_data;
3336 self = helper->mail_op;
3337 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3339 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3341 priv->done = status->position;
3342 priv->total = status->of_total;
3344 state = modest_mail_operation_clone_state (self);
3346 /* This is not a GDK lock because we are a Tinymail callback and
3347 * Tinymail already acquires the Gdk lock */
3348 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3350 g_slice_free (ModestMailOperationState, state);
3354 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3356 RefreshAsyncUserCallback user_callback,
3359 ModestMailOperationPrivate *priv = NULL;
3360 RefreshAsyncHelper *helper = NULL;
3362 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3364 /* Check memory low */
3365 if (_check_memory_low (self)) {
3367 user_callback (self, folder, user_data);
3368 /* Notify about operation end */
3369 modest_mail_operation_notify_end (self);
3373 /* Get account and set it into mail_operation */
3374 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3375 priv->account = modest_tny_folder_get_account (folder);
3376 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3378 /* Create the helper */
3379 helper = g_slice_new0 (RefreshAsyncHelper);
3380 helper->mail_op = g_object_ref(self);
3381 helper->user_callback = user_callback;
3382 helper->user_data = user_data;
3384 modest_mail_operation_notify_start (self);
3386 /* notify that the operation was started */
3387 ModestMailOperationState *state;
3388 state = modest_mail_operation_clone_state (self);
3391 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3393 g_slice_free (ModestMailOperationState, state);
3395 tny_folder_refresh_async (folder,
3397 on_refresh_folder_status_update,
3402 run_queue_notify_and_destroy (RunQueueHelper *helper,
3403 ModestMailOperationStatus status)
3405 ModestMailOperationPrivate *priv;
3408 if (helper->error_handler &&
3409 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3410 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3411 if (helper->start_handler &&
3412 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3413 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3414 if (helper->stop_handler &&
3415 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3416 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3419 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3420 priv->status = status;
3423 modest_mail_operation_notify_end (helper->self);
3426 g_object_unref (helper->queue);
3427 g_object_unref (helper->self);
3428 g_slice_free (RunQueueHelper, helper);
3432 run_queue_stop (ModestTnySendQueue *queue,
3435 RunQueueHelper *helper;
3437 g_debug ("%s sending queue stopped", __FUNCTION__);
3439 helper = (RunQueueHelper *) user_data;
3440 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3444 modest_mail_operation_run_queue (ModestMailOperation *self,
3445 ModestTnySendQueue *queue)
3447 ModestMailOperationPrivate *priv;
3448 RunQueueHelper *helper;
3450 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3451 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3452 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3454 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3455 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3456 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3458 /* Create the helper */
3459 helper = g_slice_new0 (RunQueueHelper);
3460 helper->queue = g_object_ref (queue);
3461 helper->self = g_object_ref (self);
3462 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3463 G_CALLBACK (run_queue_stop),
3466 /* Notify operation has started */
3467 modest_mail_operation_notify_start (self);
3468 g_debug ("%s, run queue started", __FUNCTION__);
3472 queue_wakeup_callback (ModestTnySendQueue *queue,
3477 ModestMailOperation *mail_op;
3478 ModestMailOperationPrivate *priv;
3480 mail_op = (ModestMailOperation *) userdata;
3481 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3483 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3484 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3487 modest_mail_operation_notify_end (mail_op);
3488 g_object_unref (mail_op);
3492 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3493 ModestTnySendQueue *queue)
3495 ModestMailOperationPrivate *priv;
3497 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3498 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3499 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3501 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3502 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3503 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3505 g_object_ref (self);
3507 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3508 modest_mail_operation_notify_start (self);
3512 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3514 ModestMailOperation *self = (ModestMailOperation *) userdata;
3515 ModestMailOperationPrivate *priv;
3517 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3518 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3521 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3523 modest_mail_operation_notify_end (self);
3524 g_object_unref (self);
3528 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3530 ModestMailOperationPrivate *priv;
3532 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3533 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3534 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3536 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3538 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3539 priv->account = NULL;
3540 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3542 modest_mail_operation_notify_start (self);
3543 g_object_ref (self);
3544 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3548 sync_folder_finish_callback (TnyFolder *self,
3554 ModestMailOperation *mail_op;
3555 ModestMailOperationPrivate *priv;
3557 mail_op = (ModestMailOperation *) user_data;
3558 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3560 /* If canceled by the user, ignore the error given by Tinymail */
3562 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3564 /* If the operation was a sync then the status is
3565 failed, but if it's part of another operation then
3566 just set it as finished with errors */
3567 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3568 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3570 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3571 priv->error = g_error_copy ((const GError *) err);
3572 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3574 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3577 modest_mail_operation_notify_end (mail_op);
3578 g_object_unref (mail_op);
3582 modest_mail_operation_sync_folder (ModestMailOperation *self,
3583 TnyFolder *folder, gboolean expunge)
3585 ModestMailOperationPrivate *priv;
3587 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3588 g_return_if_fail (TNY_IS_FOLDER (folder));
3589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3591 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3592 priv->account = modest_tny_folder_get_account (folder);
3593 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3595 modest_mail_operation_notify_start (self);
3596 g_object_ref (self);
3597 tny_folder_sync_async (folder, expunge,
3598 (TnyFolderCallback) sync_folder_finish_callback,
3603 modest_mail_operation_notify_start (ModestMailOperation *self)
3605 ModestMailOperationPrivate *priv = NULL;
3607 g_return_if_fail (self);
3609 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3611 /* Ensure that all the fields are filled correctly */
3612 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3614 /* Notify the observers about the mail operation. We do not
3615 wrapp this emission because we assume that this function is
3616 always called from within the main lock */
3617 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3622 * It's used by the mail operation queue to notify the observers
3623 * attached to that signal that the operation finished. We need to use
3624 * that because tinymail does not give us the progress of a given
3625 * operation when it finishes (it directly calls the operation
3629 modest_mail_operation_notify_end (ModestMailOperation *self)
3631 ModestMailOperationPrivate *priv = NULL;
3633 g_return_if_fail (self);
3635 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3637 /* Notify the observers about the mail operation end. We do
3638 not wrapp this emission because we assume that this
3639 function is always called from within the main lock */
3640 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3642 /* Remove the error user data */
3643 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3644 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3648 modest_mail_operation_get_account (ModestMailOperation *self)
3650 ModestMailOperationPrivate *priv = NULL;
3652 g_return_val_if_fail (self, NULL);
3654 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3656 return (priv->account) ? g_object_ref (priv->account) : NULL;
3660 modest_mail_operation_noop (ModestMailOperation *self)
3662 ModestMailOperationPrivate *priv = NULL;
3664 g_return_if_fail (self);
3666 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3667 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3668 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3672 /* This mail operation does nothing actually */
3673 modest_mail_operation_notify_start (self);
3674 modest_mail_operation_notify_end (self);
3679 modest_mail_operation_to_string (ModestMailOperation *self)
3681 const gchar *type, *status, *account_id;
3682 ModestMailOperationPrivate *priv = NULL;
3684 g_return_val_if_fail (self, NULL);
3686 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3688 /* new operations don't have anything interesting */
3689 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3690 return g_strdup_printf ("%p <new operation>", self);
3692 switch (priv->op_type) {
3693 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3694 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3695 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3696 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3697 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3698 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3699 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3700 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3701 default: type = "UNEXPECTED"; break;
3704 switch (priv->status) {
3705 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3706 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3707 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3708 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3709 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3710 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3711 default: status= "UNEXPECTED"; break;
3714 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3716 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3717 priv->done, priv->total,
3718 priv->error && priv->error->message ? priv->error->message : "");
3722 * Once the mail operations were objects this will be no longer
3723 * needed. I don't like it, but we need it for the moment
3726 _check_memory_low (ModestMailOperation *mail_op)
3728 if (modest_platform_check_memory_low (NULL, FALSE)) {
3729 ModestMailOperationPrivate *priv;
3731 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3732 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3733 g_set_error (&(priv->error),
3734 MODEST_MAIL_OPERATION_ERROR,
3735 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3736 "Not enough memory to complete the operation");