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 = 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;
2834 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2835 g_return_if_fail (TNY_IS_LIST (headers));
2837 if (remove_to_trash)
2838 g_warning ("remove to trash is not implemented");
2840 if (tny_list_get_length(headers) == 0) {
2841 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2842 goto cleanup; /* nothing to do */
2845 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2846 remove_headers = g_object_ref(headers);
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));
2852 folder = tny_header_get_folder (header);
2853 if (!TNY_IS_FOLDER(folder)) {
2854 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2858 /* Don't remove messages that are being sent */
2859 if (modest_tny_folder_is_local_folder (folder)) {
2860 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2862 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2863 TnyTransportAccount *traccount = NULL;
2864 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2865 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2867 ModestTnySendQueueStatus status;
2868 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2870 if (TNY_IS_SEND_QUEUE (send_queue)) {
2871 TnyIterator *iter = tny_list_create_iterator(headers);
2872 g_object_unref(remove_headers);
2873 remove_headers = TNY_LIST(tny_simple_list_new());
2874 while (!tny_iterator_is_done(iter)) {
2876 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2877 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2878 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2879 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2880 tny_list_append(remove_headers, G_OBJECT(hdr));
2882 g_object_unref(hdr);
2884 tny_iterator_next(iter);
2886 g_object_unref(iter);
2888 g_object_unref(traccount);
2892 /* Get account and set it into mail_operation */
2893 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2894 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2895 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2897 /* remove message from folder */
2898 modest_mail_operation_notify_start (self);
2899 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2900 NULL, g_object_ref (self));
2904 g_object_unref (remove_headers);
2906 g_object_unref (header);
2908 g_object_unref (iter);
2910 g_object_unref (folder);
2914 notify_progress_of_multiple_messages (ModestMailOperation *self,
2916 gint *last_total_bytes,
2917 gint *sum_total_bytes,
2919 gboolean increment_done)
2921 ModestMailOperationPrivate *priv;
2922 ModestMailOperationState *state;
2923 gboolean is_num_bytes = FALSE;
2925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2927 /* We know that tinymail sends us information about
2928 * transferred bytes with this particular message
2930 if (status->message)
2931 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2933 state = modest_mail_operation_clone_state (self);
2934 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2935 /* We know that we're in a different message when the
2936 total number of bytes to transfer is different. Of
2937 course it could fail if we're transferring messages
2938 of the same size, but this is a workarround */
2939 if (status->of_total != *last_total_bytes) {
2940 /* We need to increment the done when there is
2941 no information about each individual
2942 message, we need to do this in message
2943 transfers, and we don't do it for getting
2947 *sum_total_bytes += *last_total_bytes;
2948 *last_total_bytes = status->of_total;
2950 state->bytes_done += status->position + *sum_total_bytes;
2951 state->bytes_total = total_bytes;
2953 /* Notify the status change. Only notify about changes
2954 referred to bytes */
2955 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2959 g_slice_free (ModestMailOperationState, state);
2963 transfer_msgs_status_cb (GObject *obj,
2967 XFerMsgsAsyncHelper *helper;
2969 g_return_if_fail (status != NULL);
2971 /* Show only the status information we want */
2972 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2975 helper = (XFerMsgsAsyncHelper *) user_data;
2976 g_return_if_fail (helper != NULL);
2978 /* Notify progress */
2979 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2980 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2984 transfer_msgs_sync_folder_cb (TnyFolder *self,
2989 XFerMsgsAsyncHelper *helper;
2990 /* We don't care here about the results of the
2992 helper = (XFerMsgsAsyncHelper *) user_data;
2994 /* Notify about operation end */
2995 modest_mail_operation_notify_end (helper->mail_op);
2997 /* If user defined callback function was defined, call it */
2998 if (helper->user_callback)
2999 helper->user_callback (helper->mail_op, helper->user_data);
3002 if (helper->more_msgs)
3003 g_object_unref (helper->more_msgs);
3004 if (helper->headers)
3005 g_object_unref (helper->headers);
3006 if (helper->dest_folder)
3007 g_object_unref (helper->dest_folder);
3008 if (helper->mail_op)
3009 g_object_unref (helper->mail_op);
3010 g_slice_free (XFerMsgsAsyncHelper, helper);
3014 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3016 XFerMsgsAsyncHelper *helper;
3017 ModestMailOperation *self;
3018 ModestMailOperationPrivate *priv;
3019 gboolean finished = TRUE;
3021 helper = (XFerMsgsAsyncHelper *) user_data;
3022 self = helper->mail_op;
3024 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3027 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3029 priv->error = g_error_copy (err);
3031 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3032 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3033 if (helper->more_msgs) {
3034 /* We'll transfer the next message in the list */
3035 tny_iterator_next (helper->more_msgs);
3036 if (!tny_iterator_is_done (helper->more_msgs)) {
3037 GObject *next_header;
3038 g_object_unref (helper->headers);
3039 helper->headers = tny_simple_list_new ();
3040 next_header = tny_iterator_get_current (helper->more_msgs);
3041 tny_list_append (helper->headers, next_header);
3042 g_object_unref (next_header);
3048 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3053 /* Synchronize the source folder contents. This should
3054 be done by tinymail but the camel_folder_sync it's
3055 actually disabled in transfer_msgs_thread_clean
3056 because it's supposed to cause hangs */
3057 tny_folder_sync_async (folder, helper->delete,
3058 transfer_msgs_sync_folder_cb,
3061 /* Transfer more messages */
3062 tny_folder_transfer_msgs_async (folder,
3064 helper->dest_folder,
3067 transfer_msgs_status_cb,
3072 /* Computes the size of the messages the headers in the list belongs
3073 to. If num_elements is different from 0 then it only takes into
3074 account the first num_elements for the calculation */
3076 compute_message_list_size (TnyList *headers,
3080 guint size = 0, element = 0;
3082 /* If num_elements is not valid then take all into account */
3083 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3084 num_elements = tny_list_get_length (headers);
3086 iter = tny_list_create_iterator (headers);
3087 while (!tny_iterator_is_done (iter) && element < num_elements) {
3088 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3089 size += tny_header_get_message_size (header);
3090 g_object_unref (header);
3091 tny_iterator_next (iter);
3094 g_object_unref (iter);
3100 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3103 gboolean delete_original,
3104 XferMsgsAsyncUserCallback user_callback,
3107 ModestMailOperationPrivate *priv = NULL;
3108 TnyIterator *iter = NULL;
3109 TnyFolder *src_folder = NULL;
3110 XFerMsgsAsyncHelper *helper = NULL;
3111 TnyHeader *header = NULL;
3112 ModestTnyFolderRules rules = 0;
3113 TnyAccount *dst_account = NULL;
3114 gboolean leave_on_server;
3115 ModestMailOperationState *state;
3116 ModestProtocolRegistry *protocol_registry;
3117 ModestProtocolType account_protocol;
3119 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3120 g_return_if_fail (headers && TNY_IS_LIST (headers));
3121 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3123 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3124 protocol_registry = modest_runtime_get_protocol_registry ();
3126 priv->total = tny_list_get_length (headers);
3128 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3129 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3131 /* Apply folder rules */
3132 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3133 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3134 /* Set status failed and set an error */
3135 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3136 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3137 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3138 _CS("ckct_ib_unable_to_paste_here"));
3139 /* Notify the queue */
3140 modest_mail_operation_notify_end (self);
3144 /* Get source folder */
3145 iter = tny_list_create_iterator (headers);
3146 header = TNY_HEADER (tny_iterator_get_current (iter));
3148 src_folder = tny_header_get_folder (header);
3149 g_object_unref (header);
3151 g_object_unref (iter);
3153 if (src_folder == NULL) {
3154 /* Notify the queue */
3155 modest_mail_operation_notify_end (self);
3157 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3162 /* Check folder source and destination */
3163 if (src_folder == folder) {
3164 /* Set status failed and set an error */
3165 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3166 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3167 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3168 _("mail_in_ui_folder_copy_target_error"));
3170 /* Notify the queue */
3171 modest_mail_operation_notify_end (self);
3174 g_object_unref (src_folder);
3178 /* Create the helper */
3179 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3180 helper->mail_op = g_object_ref(self);
3181 helper->dest_folder = g_object_ref(folder);
3182 helper->user_callback = user_callback;
3183 helper->user_data = user_data;
3184 helper->last_total_bytes = 0;
3185 helper->sum_total_bytes = 0;
3186 helper->total_bytes = compute_message_list_size (headers, 0);
3188 /* Get account and set it into mail_operation */
3189 priv->account = modest_tny_folder_get_account (src_folder);
3190 dst_account = modest_tny_folder_get_account (folder);
3192 if (priv->account == dst_account) {
3193 /* Transfer all messages at once using the fast
3194 * method. Note that depending on the server this
3195 * might not be that fast, and might not be
3196 * user-cancellable either */
3197 helper->headers = g_object_ref (headers);
3198 helper->more_msgs = NULL;
3200 /* Transfer messages one by one so the user can cancel
3203 helper->headers = tny_simple_list_new ();
3204 helper->more_msgs = tny_list_create_iterator (headers);
3205 hdr = tny_iterator_get_current (helper->more_msgs);
3206 tny_list_append (helper->headers, hdr);
3207 g_object_unref (hdr);
3210 /* If leave_on_server is set to TRUE then don't use
3211 delete_original, we always pass FALSE. This is because
3212 otherwise tinymail will try to sync the source folder and
3213 this could cause an error if we're offline while
3214 transferring an already downloaded message from a POP
3216 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3217 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3218 const gchar *account_name;
3220 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3221 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3224 leave_on_server = FALSE;
3227 /* Do not delete messages if leave on server is TRUE */
3228 helper->delete = (leave_on_server) ? FALSE : delete_original;
3230 modest_mail_operation_notify_start (self);
3232 /* Start notifying progress */
3233 state = modest_mail_operation_clone_state (self);
3236 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3237 g_slice_free (ModestMailOperationState, state);
3239 tny_folder_transfer_msgs_async (src_folder,
3244 transfer_msgs_status_cb,
3246 g_object_unref (src_folder);
3247 g_object_unref (dst_account);
3252 on_refresh_folder (TnyFolder *folder,
3257 RefreshAsyncHelper *helper = NULL;
3258 ModestMailOperation *self = NULL;
3259 ModestMailOperationPrivate *priv = NULL;
3261 helper = (RefreshAsyncHelper *) user_data;
3262 self = helper->mail_op;
3263 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3265 g_return_if_fail(priv!=NULL);
3268 priv->error = g_error_copy (error);
3269 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3274 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3275 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3276 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3277 _("Error trying to refresh the contents of %s"),
3278 tny_folder_get_name (folder));
3282 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3285 /* Call user defined callback, if it exists */
3286 if (helper->user_callback) {
3288 /* This is not a GDK lock because we are a Tinymail callback and
3289 * Tinymail already acquires the Gdk lock */
3290 helper->user_callback (self, folder, helper->user_data);
3294 g_slice_free (RefreshAsyncHelper, helper);
3296 /* Notify about operation end */
3297 modest_mail_operation_notify_end (self);
3298 g_object_unref(self);
3302 on_refresh_folder_status_update (GObject *obj,
3306 RefreshAsyncHelper *helper = NULL;
3307 ModestMailOperation *self = NULL;
3308 ModestMailOperationPrivate *priv = NULL;
3309 ModestMailOperationState *state;
3311 g_return_if_fail (user_data != NULL);
3312 g_return_if_fail (status != NULL);
3314 /* Show only the status information we want */
3315 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3318 helper = (RefreshAsyncHelper *) user_data;
3319 self = helper->mail_op;
3320 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3324 priv->done = status->position;
3325 priv->total = status->of_total;
3327 state = modest_mail_operation_clone_state (self);
3329 /* This is not a GDK lock because we are a Tinymail callback and
3330 * Tinymail already acquires the Gdk lock */
3331 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3333 g_slice_free (ModestMailOperationState, state);
3337 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3339 RefreshAsyncUserCallback user_callback,
3342 ModestMailOperationPrivate *priv = NULL;
3343 RefreshAsyncHelper *helper = NULL;
3345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3347 /* Check memory low */
3348 if (_check_memory_low (self)) {
3350 user_callback (self, folder, user_data);
3351 /* Notify about operation end */
3352 modest_mail_operation_notify_end (self);
3356 /* Get account and set it into mail_operation */
3357 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3358 priv->account = modest_tny_folder_get_account (folder);
3359 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3361 /* Create the helper */
3362 helper = g_slice_new0 (RefreshAsyncHelper);
3363 helper->mail_op = g_object_ref(self);
3364 helper->user_callback = user_callback;
3365 helper->user_data = user_data;
3367 modest_mail_operation_notify_start (self);
3369 /* notify that the operation was started */
3370 ModestMailOperationState *state;
3371 state = modest_mail_operation_clone_state (self);
3374 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3376 g_slice_free (ModestMailOperationState, state);
3378 tny_folder_refresh_async (folder,
3380 on_refresh_folder_status_update,
3385 run_queue_notify_and_destroy (RunQueueHelper *helper,
3386 ModestMailOperationStatus status)
3388 ModestMailOperationPrivate *priv;
3391 if (helper->error_handler &&
3392 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3393 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3394 if (helper->start_handler &&
3395 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3396 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3397 if (helper->stop_handler &&
3398 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3399 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3403 priv->status = status;
3406 modest_mail_operation_notify_end (helper->self);
3409 g_object_unref (helper->queue);
3410 g_object_unref (helper->self);
3411 g_slice_free (RunQueueHelper, helper);
3415 run_queue_stop (ModestTnySendQueue *queue,
3418 RunQueueHelper *helper;
3420 g_debug ("%s sending queue stopped", __FUNCTION__);
3422 helper = (RunQueueHelper *) user_data;
3423 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3427 modest_mail_operation_run_queue (ModestMailOperation *self,
3428 ModestTnySendQueue *queue)
3430 ModestMailOperationPrivate *priv;
3431 RunQueueHelper *helper;
3433 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3434 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3437 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3438 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3439 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3441 /* Create the helper */
3442 helper = g_slice_new0 (RunQueueHelper);
3443 helper->queue = g_object_ref (queue);
3444 helper->self = g_object_ref (self);
3445 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3446 G_CALLBACK (run_queue_stop),
3449 /* Notify operation has started */
3450 modest_mail_operation_notify_start (self);
3451 g_debug ("%s, run queue started", __FUNCTION__);
3455 queue_wakeup_callback (ModestTnySendQueue *queue,
3460 ModestMailOperation *mail_op;
3461 ModestMailOperationPrivate *priv;
3463 mail_op = (ModestMailOperation *) userdata;
3464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3466 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3467 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3470 modest_mail_operation_notify_end (mail_op);
3471 g_object_unref (mail_op);
3475 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3476 ModestTnySendQueue *queue)
3478 ModestMailOperationPrivate *priv;
3480 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3481 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3484 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3485 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3486 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3488 g_object_ref (self);
3490 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3491 modest_mail_operation_notify_start (self);
3495 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3497 ModestMailOperation *self = (ModestMailOperation *) userdata;
3498 ModestMailOperationPrivate *priv;
3500 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3501 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3504 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3506 modest_mail_operation_notify_end (self);
3507 g_object_unref (self);
3511 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3513 ModestMailOperationPrivate *priv;
3515 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3516 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3517 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3519 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3521 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3522 priv->account = NULL;
3523 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3525 modest_mail_operation_notify_start (self);
3526 g_object_ref (self);
3527 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3531 sync_folder_finish_callback (TnyFolder *self,
3537 ModestMailOperation *mail_op;
3538 ModestMailOperationPrivate *priv;
3540 mail_op = (ModestMailOperation *) user_data;
3541 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3543 /* If canceled by the user, ignore the error given by Tinymail */
3545 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3547 /* If the operation was a sync then the status is
3548 failed, but if it's part of another operation then
3549 just set it as finished with errors */
3550 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3551 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3553 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3554 priv->error = g_error_copy ((const GError *) err);
3555 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3557 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3560 modest_mail_operation_notify_end (mail_op);
3561 g_object_unref (mail_op);
3565 modest_mail_operation_sync_folder (ModestMailOperation *self,
3566 TnyFolder *folder, gboolean expunge)
3568 ModestMailOperationPrivate *priv;
3570 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3571 g_return_if_fail (TNY_IS_FOLDER (folder));
3572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3574 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3575 priv->account = modest_tny_folder_get_account (folder);
3576 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3578 modest_mail_operation_notify_start (self);
3579 g_object_ref (self);
3580 tny_folder_sync_async (folder, expunge,
3581 (TnyFolderCallback) sync_folder_finish_callback,
3586 modest_mail_operation_notify_start (ModestMailOperation *self)
3588 ModestMailOperationPrivate *priv = NULL;
3590 g_return_if_fail (self);
3592 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3594 /* Ensure that all the fields are filled correctly */
3595 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3597 /* Notify the observers about the mail operation. We do not
3598 wrapp this emission because we assume that this function is
3599 always called from within the main lock */
3600 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3605 * It's used by the mail operation queue to notify the observers
3606 * attached to that signal that the operation finished. We need to use
3607 * that because tinymail does not give us the progress of a given
3608 * operation when it finishes (it directly calls the operation
3612 modest_mail_operation_notify_end (ModestMailOperation *self)
3614 ModestMailOperationPrivate *priv = NULL;
3616 g_return_if_fail (self);
3618 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3620 /* Notify the observers about the mail operation end. We do
3621 not wrapp this emission because we assume that this
3622 function is always called from within the main lock */
3623 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3625 /* Remove the error user data */
3626 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3627 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3631 modest_mail_operation_get_account (ModestMailOperation *self)
3633 ModestMailOperationPrivate *priv = NULL;
3635 g_return_val_if_fail (self, NULL);
3637 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3639 return (priv->account) ? g_object_ref (priv->account) : NULL;
3643 modest_mail_operation_noop (ModestMailOperation *self)
3645 ModestMailOperationPrivate *priv = NULL;
3647 g_return_if_fail (self);
3649 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3650 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3651 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3655 /* This mail operation does nothing actually */
3656 modest_mail_operation_notify_start (self);
3657 modest_mail_operation_notify_end (self);
3662 modest_mail_operation_to_string (ModestMailOperation *self)
3664 const gchar *type, *status, *account_id;
3665 ModestMailOperationPrivate *priv = NULL;
3667 g_return_val_if_fail (self, NULL);
3669 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3671 /* new operations don't have anything interesting */
3672 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3673 return g_strdup_printf ("%p <new operation>", self);
3675 switch (priv->op_type) {
3676 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3677 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3678 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3679 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3680 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3681 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3682 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3683 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3684 default: type = "UNEXPECTED"; break;
3687 switch (priv->status) {
3688 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3689 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3690 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3691 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3692 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3693 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3694 default: status= "UNEXPECTED"; break;
3697 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3699 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3700 priv->done, priv->total,
3701 priv->error && priv->error->message ? priv->error->message : "");
3705 * Once the mail operations were objects this will be no longer
3706 * needed. I don't like it, but we need it for the moment
3709 _check_memory_low (ModestMailOperation *mail_op)
3711 if (modest_platform_check_memory_low (NULL, FALSE)) {
3712 ModestMailOperationPrivate *priv;
3714 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3715 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3716 g_set_error (&(priv->error),
3717 MODEST_MAIL_OPERATION_ERROR,
3718 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3719 "Not enough memory to complete the operation");