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 ModestMailOperationCreateMsgCallback callback,
237 static gboolean idle_notify_queue (gpointer data);
240 ModestMailOperation *mail_op;
248 GList *attachments_list;
250 TnyHeaderFlags priority_flags;
251 ModestMailOperationCreateMsgCallback callback;
257 ModestMailOperation *mail_op;
259 ModestMailOperationCreateMsgCallback callback;
264 static GObjectClass *parent_class = NULL;
266 static guint signals[NUM_SIGNALS] = {0};
269 modest_mail_operation_get_type (void)
271 static GType my_type = 0;
273 static const GTypeInfo my_info = {
274 sizeof(ModestMailOperationClass),
275 NULL, /* base init */
276 NULL, /* base finalize */
277 (GClassInitFunc) modest_mail_operation_class_init,
278 NULL, /* class finalize */
279 NULL, /* class data */
280 sizeof(ModestMailOperation),
282 (GInstanceInitFunc) modest_mail_operation_init,
285 my_type = g_type_register_static (G_TYPE_OBJECT,
286 "ModestMailOperation",
293 modest_mail_operation_class_init (ModestMailOperationClass *klass)
295 GObjectClass *gobject_class;
296 gobject_class = (GObjectClass*) klass;
298 parent_class = g_type_class_peek_parent (klass);
299 gobject_class->finalize = modest_mail_operation_finalize;
301 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
304 * ModestMailOperation::progress-changed
305 * @self: the #MailOperation that emits the signal
306 * @user_data: user data set when the signal handler was connected
308 * Emitted when the progress of a mail operation changes
310 signals[PROGRESS_CHANGED_SIGNAL] =
311 g_signal_new ("progress-changed",
312 G_TYPE_FROM_CLASS (gobject_class),
314 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
316 g_cclosure_marshal_VOID__POINTER,
317 G_TYPE_NONE, 1, G_TYPE_POINTER);
321 * This signal is issued whenever a mail operation starts, and
322 * starts mean when the tinymail operation is issued. This
323 * means that it could happen that something wrong happens and
324 * the tinymail function is never called. In this situation a
325 * operation-finished will be issued without any
328 signals[OPERATION_STARTED_SIGNAL] =
329 g_signal_new ("operation-started",
330 G_TYPE_FROM_CLASS (gobject_class),
332 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
334 g_cclosure_marshal_VOID__VOID,
339 * This signal is issued whenever a mail operation
340 * finishes. Note that this signal could be issued without any
341 * previous "operation-started" signal, because this last one
342 * is only issued when the tinymail operation is successfully
345 signals[OPERATION_FINISHED_SIGNAL] =
346 g_signal_new ("operation-finished",
347 G_TYPE_FROM_CLASS (gobject_class),
349 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
351 g_cclosure_marshal_VOID__VOID,
356 modest_mail_operation_init (ModestMailOperation *obj)
358 ModestMailOperationPrivate *priv;
360 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
362 priv->account = NULL;
363 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
364 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
369 priv->error_checking = NULL;
370 priv->error_checking_user_data = NULL;
374 modest_mail_operation_finalize (GObject *obj)
376 ModestMailOperationPrivate *priv;
378 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
383 g_error_free (priv->error);
387 g_object_unref (priv->source);
391 g_object_unref (priv->account);
392 priv->account = NULL;
396 G_OBJECT_CLASS(parent_class)->finalize (obj);
400 modest_mail_operation_new (GObject *source)
402 ModestMailOperation *obj;
403 ModestMailOperationPrivate *priv;
405 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
409 priv->source = g_object_ref(source);
415 modest_mail_operation_new_with_error_handling (GObject *source,
416 ErrorCheckingUserCallback error_handler,
418 ErrorCheckingUserDataDestroyer error_handler_destroyer)
420 ModestMailOperation *obj;
421 ModestMailOperationPrivate *priv;
423 obj = modest_mail_operation_new (source);
424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
426 g_return_val_if_fail (error_handler != NULL, obj);
427 priv->error_checking = error_handler;
428 priv->error_checking_user_data = user_data;
429 priv->error_checking_user_data_destroyer = error_handler_destroyer;
435 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
437 ModestMailOperationPrivate *priv;
439 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
441 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
442 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
444 /* Call the user callback */
445 if (priv->error_checking != NULL)
446 priv->error_checking (self, priv->error_checking_user_data);
450 ModestMailOperationTypeOperation
451 modest_mail_operation_get_type_operation (ModestMailOperation *self)
453 ModestMailOperationPrivate *priv;
455 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
456 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
460 return priv->op_type;
464 modest_mail_operation_is_mine (ModestMailOperation *self,
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
473 if (priv->source == NULL) return FALSE;
475 return priv->source == me;
479 modest_mail_operation_get_source (ModestMailOperation *self)
481 ModestMailOperationPrivate *priv;
483 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
486 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
488 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
492 return (priv->source) ? g_object_ref (priv->source) : NULL;
495 ModestMailOperationStatus
496 modest_mail_operation_get_status (ModestMailOperation *self)
498 ModestMailOperationPrivate *priv;
500 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
501 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
502 MODEST_MAIL_OPERATION_STATUS_INVALID);
504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
506 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
507 return MODEST_MAIL_OPERATION_STATUS_INVALID;
514 modest_mail_operation_get_error (ModestMailOperation *self)
516 ModestMailOperationPrivate *priv;
518 g_return_val_if_fail (self, NULL);
519 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
521 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
524 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
532 modest_mail_operation_cancel (ModestMailOperation *self)
534 ModestMailOperationPrivate *priv;
535 gboolean canceled = FALSE;
537 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
539 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
542 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
544 /* Cancel the mail operation */
545 g_return_val_if_fail (priv->account, FALSE);
546 tny_account_cancel (priv->account);
548 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
549 ModestTnySendQueue *queue;
550 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
553 /* Cancel the sending of the following next messages */
554 if (TNY_IS_SEND_QUEUE (queue))
555 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
562 modest_mail_operation_get_task_done (ModestMailOperation *self)
564 ModestMailOperationPrivate *priv;
566 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
569 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
574 modest_mail_operation_get_task_total (ModestMailOperation *self)
576 ModestMailOperationPrivate *priv;
578 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
581 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
586 modest_mail_operation_is_finished (ModestMailOperation *self)
588 ModestMailOperationPrivate *priv;
589 gboolean retval = FALSE;
591 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
594 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
596 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
597 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
598 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
599 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
609 * Creates an image of the current state of a mail operation, the
610 * caller must free it
612 static ModestMailOperationState *
613 modest_mail_operation_clone_state (ModestMailOperation *self)
615 ModestMailOperationState *state;
616 ModestMailOperationPrivate *priv;
618 g_return_val_if_fail (self, NULL);
619 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
620 g_return_val_if_fail (priv, NULL);
625 state = g_slice_new (ModestMailOperationState);
627 state->status = priv->status;
628 state->op_type = priv->op_type;
629 state->done = priv->done;
630 state->total = priv->total;
631 state->finished = modest_mail_operation_is_finished (self);
632 state->bytes_done = 0;
633 state->bytes_total = 0;
638 /* ******************************************************************* */
639 /* ************************** SEND ACTIONS ************************* */
640 /* ******************************************************************* */
644 ModestMailOperation *mail_op;
649 send_mail_on_sync_async_cb (TnyFolder *folder,
654 ModestMailOperationPrivate *priv;
655 ModestMailOperation *self;
656 SendNewMailHelper *helper;
658 helper = (SendNewMailHelper *) user_data;
659 self = helper->mail_op;
660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
662 if (cancelled || err)
666 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
667 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
668 "Error adding a msg to the send queue\n");
669 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
671 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
676 modest_mail_operation_notify_end (self);
678 g_object_unref (helper->mail_op);
679 g_slice_free (SendNewMailHelper, helper);
683 run_queue_start (TnySendQueue *self,
686 RunQueueHelper *helper = (RunQueueHelper *) user_data;
687 ModestMailOperation *mail_op;
689 g_debug ("%s sending queue successfully started", __FUNCTION__);
691 /* Wait for the message to be sent */
692 mail_op = modest_mail_operation_new (NULL);
693 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
695 modest_mail_operation_run_queue (mail_op, helper->queue);
696 g_object_unref (mail_op);
698 /* Free the helper and end operation */
699 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
703 run_queue_error_happened (TnySendQueue *queue,
709 RunQueueHelper *helper = (RunQueueHelper *) user_data;
710 ModestMailOperationPrivate *priv;
712 /* If we are here this means that the send queue could not
713 start to send emails. Shouldn't happen as this means that
714 we could not create the thread */
715 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
717 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
718 priv->error = g_error_copy ((const GError *) error);
720 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
721 /* This code is here for safety reasons. It should
722 never be called, because that would mean that we
723 are not controlling some error case */
724 g_warning ("%s Error %s should not happen",
725 __FUNCTION__, error->message);
728 /* Free helper and end operation */
729 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
733 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
739 ModestMailOperationPrivate *priv;
740 ModestMailOperation *self;
741 SendNewMailHelper *helper;
743 helper = (SendNewMailHelper *) user_data;
744 self = helper->mail_op;
745 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
747 if (cancelled || err)
751 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
752 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
753 "Error adding a msg to the send queue\n");
754 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
756 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
760 if (helper->notify) {
761 TnyTransportAccount *trans_account;
762 ModestTnySendQueue *queue;
764 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
765 queue = modest_runtime_get_send_queue (trans_account, TRUE);
767 RunQueueHelper *helper;
769 /* Create the helper */
770 helper = g_slice_new0 (RunQueueHelper);
771 helper->queue = g_object_ref (queue);
772 helper->self = g_object_ref (self);
774 /* if sending is ongoing wait for the queue to
775 stop. Otherwise wait for the queue-start
776 signal. It could happen that the queue
777 could not start, then check also the error
779 if (modest_tny_send_queue_sending_in_progress (queue)) {
780 run_queue_start (TNY_SEND_QUEUE (queue), helper);
782 helper->start_handler = g_signal_connect (queue, "queue-start",
783 G_CALLBACK (run_queue_start),
785 helper->error_handler = g_signal_connect (queue, "error-happened",
786 G_CALLBACK (run_queue_error_happened),
790 /* Finalize this mail operation */
791 modest_mail_operation_notify_end (self);
793 g_object_unref (trans_account);
796 g_object_unref (helper->mail_op);
797 g_slice_free (SendNewMailHelper, helper);
801 idle_create_msg_cb (gpointer idle_data)
803 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
805 /* This is a GDK lock because we are an idle callback and
806 * info->callback can contain Gtk+ code */
808 gdk_threads_enter (); /* CHECKED */
809 info->callback (info->mail_op, info->msg, info->userdata);
811 g_object_unref (info->mail_op);
813 g_object_unref (info->msg);
814 g_slice_free (CreateMsgIdleInfo, info);
815 gdk_threads_leave (); /* CHECKED */
821 create_msg_thread (gpointer thread_data)
823 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
824 TnyMsg *new_msg = NULL;
825 ModestMailOperationPrivate *priv;
828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
829 if (info->html_body == NULL) {
830 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
831 info->bcc, info->subject, info->plain_body,
832 info->attachments_list, &attached,
835 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
836 info->bcc, info->subject, info->html_body,
837 info->plain_body, info->attachments_list,
838 info->images_list, &attached,
845 /* Set priority flags in message */
846 header = tny_msg_get_header (new_msg);
847 tny_header_set_flag (header, info->priority_flags);
849 /* Set attachment flags in message */
850 if (info->attachments_list != NULL && attached > 0)
851 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
853 g_object_unref (G_OBJECT(header));
855 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
857 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
858 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
859 "modest: failed to create a new msg\n");
867 g_free (info->plain_body);
868 g_free (info->html_body);
869 g_free (info->subject);
870 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
871 g_list_free (info->attachments_list);
872 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
873 g_list_free (info->images_list);
875 if (info->callback) {
876 CreateMsgIdleInfo *idle_info;
877 idle_info = g_slice_new0 (CreateMsgIdleInfo);
878 idle_info->mail_op = g_object_ref (info->mail_op);
879 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
880 idle_info->callback = info->callback;
881 idle_info->userdata = info->userdata;
882 g_idle_add (idle_create_msg_cb, idle_info);
884 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
887 g_object_unref (info->mail_op);
888 g_slice_free (CreateMsgInfo, info);
889 if (new_msg) g_object_unref(new_msg);
895 modest_mail_operation_create_msg (ModestMailOperation *self,
896 const gchar *from, const gchar *to,
897 const gchar *cc, const gchar *bcc,
898 const gchar *subject, const gchar *plain_body,
899 const gchar *html_body,
900 const GList *attachments_list,
901 const GList *images_list,
902 TnyHeaderFlags priority_flags,
903 ModestMailOperationCreateMsgCallback callback,
906 CreateMsgInfo *info = NULL;
908 info = g_slice_new0 (CreateMsgInfo);
909 info->mail_op = g_object_ref (self);
911 info->from = g_strdup (from);
912 info->to = g_strdup (to);
913 info->cc = g_strdup (cc);
914 info->bcc = g_strdup (bcc);
915 info->subject = g_strdup (subject);
916 info->plain_body = g_strdup (plain_body);
917 info->html_body = g_strdup (html_body);
918 info->attachments_list = g_list_copy ((GList *) attachments_list);
919 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
920 info->images_list = g_list_copy ((GList *) images_list);
921 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
922 info->priority_flags = priority_flags;
924 info->callback = callback;
925 info->userdata = userdata;
927 g_thread_create (create_msg_thread, info, FALSE, NULL);
932 TnyTransportAccount *transport_account;
937 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
941 TnySendQueue *send_queue = NULL;
942 ModestMailOperationPrivate *priv = NULL;
943 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
944 TnyFolder *draft_folder = NULL;
945 TnyFolder *outbox_folder = NULL;
946 TnyHeader *header = NULL;
948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
951 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
952 modest_mail_operation_notify_end (self);
956 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
957 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
958 modest_mail_operation_notify_end (self);
962 /* Add message to send queue */
963 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
964 if (!TNY_IS_SEND_QUEUE(send_queue)) {
966 g_error_free (priv->error);
969 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
970 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
971 "modest: could not find send queue for account\n");
972 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
973 modest_mail_operation_notify_end (self);
976 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
977 helper->mail_op = g_object_ref (self);
978 helper->notify = (info->draft_msg == NULL);
980 /* Add the msg to the queue. The callback will free
982 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
984 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
988 if (info->draft_msg != NULL) {
989 TnyList *tmp_headers = NULL;
990 TnyFolder *folder = NULL;
991 TnyFolder *src_folder = NULL;
992 TnyFolderType folder_type;
993 TnyTransportAccount *transport_account = NULL;
994 SendNewMailHelper *helper = NULL;
996 /* To remove the old mail from its source folder, we need to get the
997 * transport account of the original draft message (the transport account
998 * might have been changed by the user) */
999 header = tny_msg_get_header (info->draft_msg);
1000 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1001 modest_runtime_get_account_store(), header);
1002 if (transport_account == NULL)
1003 transport_account = g_object_ref(info->transport_account);
1004 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1005 TNY_FOLDER_TYPE_DRAFTS);
1006 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1007 TNY_FOLDER_TYPE_OUTBOX);
1008 g_object_unref(transport_account);
1010 if (!draft_folder) {
1011 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1013 modest_mail_operation_notify_end (self);
1016 if (!outbox_folder) {
1017 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1019 modest_mail_operation_notify_end (self);
1023 folder = tny_msg_get_folder (info->draft_msg);
1024 if (folder == NULL) {
1025 modest_mail_operation_notify_end (self);
1028 folder_type = modest_tny_folder_guess_folder_type (folder);
1030 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1031 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1033 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1034 src_folder = outbox_folder;
1036 src_folder = draft_folder;
1038 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1039 * because this function requires it to have a UID. */
1040 helper = g_slice_new (SendNewMailHelper);
1041 helper->mail_op = g_object_ref (self);
1042 helper->notify = TRUE;
1044 tmp_headers = tny_simple_list_new ();
1045 tny_list_append (tmp_headers, (GObject*) header);
1046 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1047 g_object_unref (tmp_headers);
1048 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1050 g_object_unref (folder);
1055 g_object_unref (header);
1056 if (info->draft_msg)
1057 g_object_unref (info->draft_msg);
1059 g_object_unref (draft_folder);
1061 g_object_unref (outbox_folder);
1062 if (info->transport_account)
1063 g_object_unref (info->transport_account);
1064 g_slice_free (SendNewMailInfo, info);
1068 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1069 TnyTransportAccount *transport_account,
1071 const gchar *from, const gchar *to,
1072 const gchar *cc, const gchar *bcc,
1073 const gchar *subject, const gchar *plain_body,
1074 const gchar *html_body,
1075 const GList *attachments_list,
1076 const GList *images_list,
1077 TnyHeaderFlags priority_flags)
1079 ModestMailOperationPrivate *priv = NULL;
1080 SendNewMailInfo *info;
1082 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1083 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1086 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1087 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1088 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1090 modest_mail_operation_notify_start (self);
1092 /* Check parametters */
1094 /* Set status failed and set an error */
1095 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1096 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1097 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1098 _("Error trying to send a mail. You need to set at least one recipient"));
1099 modest_mail_operation_notify_end (self);
1102 info = g_slice_new0 (SendNewMailInfo);
1103 info->transport_account = transport_account;
1104 if (transport_account)
1105 g_object_ref (transport_account);
1106 info->draft_msg = draft_msg;
1108 g_object_ref (draft_msg);
1111 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1112 attachments_list, images_list, priority_flags,
1113 modest_mail_operation_send_new_mail_cb, info);
1119 TnyTransportAccount *transport_account;
1121 SaveToDraftstCallback callback;
1125 ModestMailOperation *mailop;
1126 } SaveToDraftsAddMsgInfo;
1129 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1134 ModestMailOperationPrivate *priv = NULL;
1135 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1136 GError *io_error = NULL;
1138 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1140 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1141 io_error = priv->error;
1145 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1146 g_error_free(priv->error);
1149 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1151 if ((!priv->error) && (info->draft_msg != NULL)) {
1152 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1153 TnyFolder *src_folder = tny_header_get_folder (header);
1155 g_debug ("--- REMOVE AND SYNC");
1156 /* Remove the old draft */
1157 tny_folder_remove_msg (src_folder, header, NULL);
1159 /* Synchronize to expunge and to update the msg counts */
1160 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1161 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1162 g_debug ("--- REMOVED - SYNCED");
1164 g_object_unref (G_OBJECT(header));
1165 g_object_unref (G_OBJECT(src_folder));
1169 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1171 g_error_free (io_error);
1174 } else if (io_error) {
1175 priv->error = io_error;
1176 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1178 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1181 /* Call the user callback */
1183 info->callback (info->mailop, info->msg, info->user_data);
1185 if (info->transport_account)
1186 g_object_unref (G_OBJECT(info->transport_account));
1187 if (info->draft_msg)
1188 g_object_unref (G_OBJECT (info->draft_msg));
1190 g_object_unref (G_OBJECT(info->drafts));
1192 g_object_unref (G_OBJECT (info->msg));
1194 modest_mail_operation_notify_end (info->mailop);
1195 g_object_unref(info->mailop);
1196 g_slice_free (SaveToDraftsAddMsgInfo, info);
1201 TnyTransportAccount *transport_account;
1203 SaveToDraftstCallback callback;
1208 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1212 TnyFolder *drafts = NULL;
1213 ModestMailOperationPrivate *priv = NULL;
1214 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1216 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1219 if (!(priv->error)) {
1220 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1221 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1222 "modest: failed to create a new msg\n");
1225 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1226 TNY_FOLDER_TYPE_DRAFTS);
1227 if (!drafts && !(priv->error)) {
1228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1229 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1230 "modest: failed to create a new msg\n");
1234 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1236 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1237 cb_info->transport_account = g_object_ref(info->transport_account);
1238 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1239 cb_info->callback = info->callback;
1240 cb_info->user_data = info->user_data;
1241 cb_info->drafts = g_object_ref(drafts);
1242 cb_info->msg = g_object_ref(msg);
1243 cb_info->mailop = g_object_ref(self);
1244 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1248 /* Call the user callback */
1249 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1251 info->callback (self, msg, info->user_data);
1252 modest_mail_operation_notify_end (self);
1256 g_object_unref (G_OBJECT(drafts));
1257 if (info->draft_msg)
1258 g_object_unref (G_OBJECT (info->draft_msg));
1259 if (info->transport_account)
1260 g_object_unref (G_OBJECT(info->transport_account));
1261 g_slice_free (SaveToDraftsInfo, info);
1265 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1266 TnyTransportAccount *transport_account,
1268 const gchar *from, const gchar *to,
1269 const gchar *cc, const gchar *bcc,
1270 const gchar *subject, const gchar *plain_body,
1271 const gchar *html_body,
1272 const GList *attachments_list,
1273 const GList *images_list,
1274 TnyHeaderFlags priority_flags,
1275 SaveToDraftstCallback callback,
1278 ModestMailOperationPrivate *priv = NULL;
1279 SaveToDraftsInfo *info = NULL;
1281 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1282 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1286 /* Get account and set it into mail_operation */
1287 priv->account = g_object_ref (transport_account);
1288 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1290 info = g_slice_new0 (SaveToDraftsInfo);
1291 info->transport_account = g_object_ref (transport_account);
1292 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1293 info->callback = callback;
1294 info->user_data = user_data;
1296 g_debug ("--- CREATE MESSAGE");
1297 modest_mail_operation_notify_start (self);
1298 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1299 attachments_list, images_list, priority_flags,
1300 modest_mail_operation_save_to_drafts_cb, info);
1305 ModestMailOperation *mail_op;
1306 TnyMimePart *mime_part;
1308 GetMimePartSizeCallback callback;
1310 } GetMimePartSizeInfo;
1312 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1313 /* We use this folder observer to track the headers that have been
1314 * added to a folder */
1317 TnyList *new_headers;
1318 } InternalFolderObserver;
1321 GObjectClass parent;
1322 } InternalFolderObserverClass;
1324 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1326 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1327 internal_folder_observer,
1329 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1333 foreach_add_item (gpointer header, gpointer user_data)
1335 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1338 /* This is the method that looks for new messages in a folder */
1340 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1342 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1344 TnyFolderChangeChanged changed;
1346 changed = tny_folder_change_get_changed (change);
1348 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1351 /* Get added headers */
1352 list = tny_simple_list_new ();
1353 tny_folder_change_get_added_headers (change, list);
1355 /* Add them to the folder observer */
1356 tny_list_foreach (list, foreach_add_item,
1357 derived->new_headers);
1359 g_object_unref (G_OBJECT (list));
1364 internal_folder_observer_init (InternalFolderObserver *self)
1366 self->new_headers = tny_simple_list_new ();
1369 internal_folder_observer_finalize (GObject *object)
1371 InternalFolderObserver *self;
1373 self = (InternalFolderObserver *) object;
1374 g_object_unref (self->new_headers);
1376 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1379 tny_folder_observer_init (TnyFolderObserverIface *iface)
1381 iface->update = internal_folder_observer_update;
1384 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1386 GObjectClass *object_class;
1388 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1389 object_class = (GObjectClass*) klass;
1390 object_class->finalize = internal_folder_observer_finalize;
1394 destroy_update_account_info (UpdateAccountInfo *info)
1396 g_free (info->account_name);
1397 g_object_unref (info->folders);
1398 g_object_unref (info->mail_op);
1399 g_slice_free (UpdateAccountInfo, info);
1404 update_account_send_mail (UpdateAccountInfo *info)
1406 TnyTransportAccount *transport_account = NULL;
1407 ModestTnyAccountStore *account_store;
1409 account_store = modest_runtime_get_account_store ();
1411 /* We don't try to send messages while sending mails is blocked */
1412 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1415 /* Get the transport account */
1416 transport_account = (TnyTransportAccount *)
1417 modest_tny_account_store_get_server_account (account_store, info->account_name,
1418 TNY_ACCOUNT_TYPE_TRANSPORT);
1420 if (transport_account) {
1421 ModestTnySendQueue *send_queue;
1425 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1426 g_object_unref (transport_account);
1428 if (TNY_IS_SEND_QUEUE (send_queue)) {
1429 /* Get outbox folder */
1430 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1431 if (outbox) { /* this could fail in some cases */
1432 num_messages = tny_folder_get_all_count (outbox);
1433 g_object_unref (outbox);
1435 g_warning ("%s: could not get outbox", __FUNCTION__);
1439 if (num_messages != 0) {
1440 ModestMailOperation *mail_op;
1441 /* Reenable suspended items */
1442 mail_op = modest_mail_operation_new (NULL);
1443 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1445 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1448 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1456 update_account_get_msg_async_cb (TnyFolder *folder,
1462 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1463 ModestMailOperationPrivate *priv;
1465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1468 if (TNY_IS_MSG (msg)) {
1469 TnyHeader *header = tny_msg_get_header (msg);
1472 ModestMailOperationState *state;
1473 state = modest_mail_operation_clone_state (msg_info->mail_op);
1474 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1475 state->bytes_done = msg_info->sum_total_bytes;
1476 state->bytes_total = msg_info->total_bytes;
1478 /* Notify the status change. Only notify about changes
1479 referred to bytes */
1480 g_signal_emit (G_OBJECT (msg_info->mail_op),
1481 signals[PROGRESS_CHANGED_SIGNAL],
1484 g_object_unref (header);
1485 g_slice_free (ModestMailOperationState, state);
1489 if (priv->done == priv->total) {
1490 TnyList *new_headers;
1491 UpdateAccountInfo *info;
1493 /* After getting all the messages send the ones in the
1495 info = (UpdateAccountInfo *) msg_info->user_data;
1496 update_account_send_mail (info);
1498 /* Check if the operation was a success */
1500 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1502 /* Call the user callback and free */
1503 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1504 update_account_notify_user_and_free (info, new_headers);
1505 g_object_unref (new_headers);
1507 /* Delete the helper */
1508 g_object_unref (msg_info->more_msgs);
1509 g_object_unref (msg_info->mail_op);
1510 g_slice_free (GetMsgInfo, msg_info);
1515 update_account_notify_user_and_free (UpdateAccountInfo *info,
1516 TnyList *new_headers)
1518 /* Set the account back to not busy */
1519 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1520 info->account_name, FALSE);
1524 info->callback (info->mail_op, new_headers, info->user_data);
1526 /* Mail operation end */
1527 modest_mail_operation_notify_end (info->mail_op);
1531 g_object_unref (new_headers);
1532 destroy_update_account_info (info);
1536 inbox_refreshed_cb (TnyFolder *inbox,
1541 UpdateAccountInfo *info;
1542 ModestMailOperationPrivate *priv;
1543 TnyIterator *new_headers_iter;
1544 GPtrArray *new_headers_array = NULL;
1545 gint max_size, retrieve_limit, i;
1546 ModestAccountMgr *mgr;
1547 ModestAccountRetrieveType retrieve_type;
1548 TnyList *new_headers = NULL;
1549 gboolean headers_only, ignore_limit;
1551 info = (UpdateAccountInfo *) user_data;
1552 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1553 mgr = modest_runtime_get_account_mgr ();
1555 if (canceled || err) {
1556 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1558 priv->error = g_error_copy (err);
1560 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1561 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1565 tny_folder_remove_observer (inbox, info->inbox_observer);
1566 g_object_unref (info->inbox_observer);
1567 info->inbox_observer = NULL;
1569 /* Notify the user about the error and then exit */
1570 update_account_notify_user_and_free (info, NULL);
1575 /* Try to send anyway */
1579 /* Set the last updated as the current time */
1580 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1582 /* Get the message max size */
1583 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1584 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1586 max_size = G_MAXINT;
1588 max_size = max_size * KB;
1590 /* Create the new headers array. We need it to sort the
1591 new headers by date */
1592 new_headers_array = g_ptr_array_new ();
1593 if (info->inbox_observer) {
1594 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1595 while (!tny_iterator_is_done (new_headers_iter)) {
1596 TnyHeader *header = NULL;
1598 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1599 /* Apply per-message size limits */
1600 if (tny_header_get_message_size (header) < max_size)
1601 g_ptr_array_add (new_headers_array, g_object_ref (header));
1603 g_object_unref (header);
1604 tny_iterator_next (new_headers_iter);
1606 g_object_unref (new_headers_iter);
1608 tny_folder_remove_observer (inbox, info->inbox_observer);
1609 g_object_unref (info->inbox_observer);
1610 info->inbox_observer = NULL;
1613 if (new_headers_array->len == 0) {
1614 g_ptr_array_free (new_headers_array, FALSE);
1618 /* Get per-account message amount retrieval limit */
1619 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1620 if (retrieve_limit == 0)
1621 retrieve_limit = G_MAXINT;
1623 /* Get per-account retrieval type */
1624 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1625 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1628 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1630 /* Ask the users if they want to retrieve all the messages
1631 even though the limit was exceeded */
1632 ignore_limit = FALSE;
1633 if (new_headers_array->len > retrieve_limit) {
1634 /* Ask the user if a callback has been specified and
1635 if the mail operation has a source (this means that
1636 was invoked by the user and not automatically by a
1638 if (info->retrieve_all_cb && priv->source)
1639 ignore_limit = info->retrieve_all_cb (priv->source,
1640 new_headers_array->len,
1644 /* Copy the headers to a list and free the array */
1645 new_headers = tny_simple_list_new ();
1646 for (i=0; i < new_headers_array->len; i++) {
1647 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1648 tny_list_append (new_headers, G_OBJECT (header));
1650 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1651 g_ptr_array_free (new_headers_array, FALSE);
1653 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1656 GetMsgInfo *msg_info;
1660 priv->total = tny_list_get_length (new_headers);
1662 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1664 iter = tny_list_create_iterator (new_headers);
1666 /* Create the message info */
1667 msg_info = g_slice_new0 (GetMsgInfo);
1668 msg_info->mail_op = g_object_ref (info->mail_op);
1669 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1670 msg_info->more_msgs = g_object_ref (iter);
1671 msg_info->user_data = info;
1673 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1674 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1675 TnyFolder *folder = tny_header_get_folder (header);
1677 /* Get message in an async way */
1678 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1681 g_object_unref (folder);
1684 tny_iterator_next (iter);
1686 g_object_unref (iter);
1688 /* The mail operation will finish when the last
1689 message is retrieved */
1693 /* If we don't have to retrieve the new messages then
1695 update_account_send_mail (info);
1697 /* Check if the operation was a success */
1699 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1701 /* Call the user callback and free */
1702 update_account_notify_user_and_free (info, new_headers);
1706 inbox_refresh_status_update (GObject *obj,
1710 UpdateAccountInfo *info = NULL;
1711 ModestMailOperation *self = NULL;
1712 ModestMailOperationPrivate *priv = NULL;
1713 ModestMailOperationState *state;
1715 g_return_if_fail (user_data != NULL);
1716 g_return_if_fail (status != NULL);
1718 /* Show only the status information we want */
1719 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1722 info = (UpdateAccountInfo *) user_data;
1723 self = info->mail_op;
1724 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1726 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1728 priv->done = status->position;
1729 priv->total = status->of_total;
1731 state = modest_mail_operation_clone_state (self);
1733 /* This is not a GDK lock because we are a Tinymail callback and
1734 * Tinymail already acquires the Gdk lock */
1735 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1737 g_slice_free (ModestMailOperationState, state);
1741 recurse_folders_async_cb (TnyFolderStore *folder_store,
1747 UpdateAccountInfo *info;
1748 ModestMailOperationPrivate *priv;
1750 info = (UpdateAccountInfo *) user_data;
1751 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1753 if (err || canceled) {
1754 /* If the error was previosly set by another callback
1755 don't set it again */
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1759 priv->error = g_error_copy (err);
1761 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1762 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1766 /* We're not getting INBOX children if we don't want to poke all */
1767 TnyIterator *iter = tny_list_create_iterator (list);
1768 while (!tny_iterator_is_done (iter)) {
1769 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1771 /* Add to the list of all folders */
1772 tny_list_append (info->folders, (GObject *) folder);
1774 if (info->poke_all) {
1775 TnyList *folders = tny_simple_list_new ();
1776 /* Add pending call */
1777 info->pending_calls++;
1779 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1780 recurse_folders_async_cb,
1782 g_object_unref (folders);
1785 g_object_unref (G_OBJECT (folder));
1787 tny_iterator_next (iter);
1789 g_object_unref (G_OBJECT (iter));
1792 /* Remove my own pending call */
1793 info->pending_calls--;
1795 /* This means that we have all the folders */
1796 if (info->pending_calls == 0) {
1797 TnyIterator *iter_all_folders;
1798 TnyFolder *inbox = NULL;
1800 /* If there was any error do not continue */
1802 update_account_notify_user_and_free (info, NULL);
1806 iter_all_folders = tny_list_create_iterator (info->folders);
1808 /* Do a poke status over all folders */
1809 while (!tny_iterator_is_done (iter_all_folders) &&
1810 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1811 TnyFolder *folder = NULL;
1813 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1815 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1816 /* Get a reference to the INBOX */
1817 inbox = g_object_ref (folder);
1819 /* Issue a poke status over the folder */
1821 tny_folder_poke_status (folder);
1824 /* Free and go to next */
1825 g_object_unref (folder);
1826 tny_iterator_next (iter_all_folders);
1828 g_object_unref (iter_all_folders);
1830 /* Refresh the INBOX */
1832 /* Refresh the folder. Our observer receives
1833 * the new emails during folder refreshes, so
1834 * we can use observer->new_headers
1836 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1837 tny_folder_add_observer (inbox, info->inbox_observer);
1839 /* Refresh the INBOX */
1840 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1841 g_object_unref (inbox);
1843 /* We could not perform the inbox refresh but
1844 we'll try to send mails anyway */
1845 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1851 modest_mail_operation_update_account (ModestMailOperation *self,
1852 const gchar *account_name,
1854 gboolean interactive,
1855 RetrieveAllCallback retrieve_all_cb,
1856 UpdateAccountCallback callback,
1859 UpdateAccountInfo *info = NULL;
1860 ModestMailOperationPrivate *priv = NULL;
1861 ModestTnyAccountStore *account_store = NULL;
1863 ModestMailOperationState *state;
1865 /* Init mail operation */
1866 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1869 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1870 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1872 /* Get the store account */
1873 account_store = modest_runtime_get_account_store ();
1875 modest_tny_account_store_get_server_account (account_store,
1877 TNY_ACCOUNT_TYPE_STORE);
1879 /* The above function could return NULL */
1880 if (!priv->account) {
1881 /* Check if the operation was a success */
1882 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1883 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1885 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1887 /* Call the user callback */
1889 callback (self, NULL, user_data);
1891 /* Notify about operation end */
1892 modest_mail_operation_notify_end (self);
1897 /* We have once seen priv->account getting finalized during this code,
1898 * therefore adding a reference (bug #82296) */
1900 g_object_ref (priv->account);
1902 /* Create the helper object */
1903 info = g_slice_new0 (UpdateAccountInfo);
1904 info->pending_calls = 1;
1905 info->folders = tny_simple_list_new ();
1906 info->mail_op = g_object_ref (self);
1907 info->poke_all = poke_all;
1908 info->interactive = interactive;
1909 info->account_name = g_strdup (account_name);
1910 info->callback = callback;
1911 info->user_data = user_data;
1912 info->retrieve_all_cb = retrieve_all_cb;
1914 /* Set account busy */
1915 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1916 modest_mail_operation_notify_start (self);
1918 /* notify about the start of the operation */
1919 state = modest_mail_operation_clone_state (self);
1923 /* Start notifying progress */
1924 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1925 g_slice_free (ModestMailOperationState, state);
1927 /* Get all folders and continue in the callback */
1928 folders = tny_simple_list_new ();
1929 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1930 folders, NULL, FALSE,
1931 recurse_folders_async_cb,
1933 g_object_unref (folders);
1935 g_object_unref (priv->account);
1940 * Used to notify the queue from the main
1941 * loop. We call it inside an idle call to achieve that
1944 idle_notify_queue (gpointer data)
1946 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1948 gdk_threads_enter ();
1949 modest_mail_operation_notify_end (mail_op);
1950 gdk_threads_leave ();
1951 g_object_unref (mail_op);
1957 compare_headers_by_date (gconstpointer a,
1960 TnyHeader **header1, **header2;
1961 time_t sent1, sent2;
1963 header1 = (TnyHeader **) a;
1964 header2 = (TnyHeader **) b;
1966 sent1 = tny_header_get_date_sent (*header1);
1967 sent2 = tny_header_get_date_sent (*header2);
1969 /* We want the most recent ones (greater time_t) at the
1978 /* ******************************************************************* */
1979 /* ************************** STORE ACTIONS ************************* */
1980 /* ******************************************************************* */
1983 ModestMailOperation *mail_op;
1984 CreateFolderUserCallback callback;
1990 create_folder_cb (TnyFolderStore *parent_folder,
1992 TnyFolder *new_folder,
1996 ModestMailOperationPrivate *priv;
1997 CreateFolderInfo *info;
1999 info = (CreateFolderInfo *) user_data;
2000 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2002 if (canceled || err) {
2003 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2005 priv->error = g_error_copy (err);
2007 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2008 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2011 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2014 /* The user will unref the new_folder */
2016 info->callback (info->mail_op, parent_folder,
2017 new_folder, info->user_data);
2019 /* Notify about operation end */
2020 modest_mail_operation_notify_end (info->mail_op);
2023 g_object_unref (info->mail_op);
2024 g_slice_free (CreateFolderInfo, info);
2028 modest_mail_operation_create_folder (ModestMailOperation *self,
2029 TnyFolderStore *parent,
2031 CreateFolderUserCallback callback,
2034 ModestMailOperationPrivate *priv;
2036 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2037 g_return_if_fail (name);
2039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2040 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2041 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2042 g_object_ref (parent) :
2043 modest_tny_folder_get_account (TNY_FOLDER (parent));
2045 /* Check for already existing folder */
2046 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2047 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2048 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2049 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2050 _CS("ckdg_ib_folder_already_exists"));
2054 if (TNY_IS_FOLDER (parent)) {
2055 /* Check folder rules */
2056 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2057 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2058 /* Set status failed and set an error */
2059 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2060 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2061 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2062 _("mail_in_ui_folder_create_error"));
2066 if (!strcmp (name, " ") || strchr (name, '/')) {
2067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2068 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2069 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2070 _("mail_in_ui_folder_create_error"));
2074 CreateFolderInfo *info;
2076 info = g_slice_new0 (CreateFolderInfo);
2077 info->mail_op = g_object_ref (self);
2078 info->callback = callback;
2079 info->user_data = user_data;
2081 modest_mail_operation_notify_start (self);
2083 /* Create the folder */
2084 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2087 /* Call the user callback anyway */
2089 callback (self, parent, NULL, user_data);
2090 /* Notify about operation end */
2091 modest_mail_operation_notify_end (self);
2096 modest_mail_operation_remove_folder (ModestMailOperation *self,
2098 gboolean remove_to_trash)
2100 ModestMailOperationPrivate *priv;
2101 ModestTnyFolderRules rules;
2103 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2104 g_return_if_fail (TNY_IS_FOLDER (folder));
2106 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2108 /* Check folder rules */
2109 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2110 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2111 /* Set status failed and set an error */
2112 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2113 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2114 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2115 _("mail_in_ui_folder_delete_error"));
2119 /* Get the account */
2120 priv->account = modest_tny_folder_get_account (folder);
2121 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2123 /* Delete folder or move to trash */
2124 if (remove_to_trash) {
2125 TnyFolder *trash_folder = NULL;
2126 trash_folder = modest_tny_account_get_special_folder (priv->account,
2127 TNY_FOLDER_TYPE_TRASH);
2128 /* TODO: error_handling */
2130 modest_mail_operation_notify_start (self);
2131 modest_mail_operation_xfer_folder (self, folder,
2132 TNY_FOLDER_STORE (trash_folder),
2134 g_object_unref (trash_folder);
2136 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2139 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2141 modest_mail_operation_notify_start (self);
2142 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2143 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2146 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2148 g_object_unref (parent);
2150 g_warning ("%s: could not get parent folder", __FUNCTION__);
2154 /* Notify about operation end */
2155 modest_mail_operation_notify_end (self);
2159 transfer_folder_status_cb (GObject *obj,
2163 ModestMailOperation *self;
2164 ModestMailOperationPrivate *priv;
2165 ModestMailOperationState *state;
2166 XFerFolderAsyncHelper *helper;
2168 g_return_if_fail (status != NULL);
2170 /* Show only the status information we want */
2171 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2174 helper = (XFerFolderAsyncHelper *) user_data;
2175 g_return_if_fail (helper != NULL);
2177 self = helper->mail_op;
2178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2180 priv->done = status->position;
2181 priv->total = status->of_total;
2183 state = modest_mail_operation_clone_state (self);
2185 /* This is not a GDK lock because we are a Tinymail callback
2186 * which is already GDK locked by Tinymail */
2188 /* no gdk_threads_enter (), CHECKED */
2190 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2192 /* no gdk_threads_leave (), CHECKED */
2194 g_slice_free (ModestMailOperationState, state);
2198 transfer_folder_cb (TnyFolder *folder,
2200 TnyFolderStore *into,
2201 TnyFolder *new_folder,
2205 XFerFolderAsyncHelper *helper;
2206 ModestMailOperation *self = NULL;
2207 ModestMailOperationPrivate *priv = NULL;
2209 helper = (XFerFolderAsyncHelper *) user_data;
2210 g_return_if_fail (helper != NULL);
2212 self = helper->mail_op;
2213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2216 priv->error = g_error_copy (err);
2218 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2219 } else if (cancelled) {
2220 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2221 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2222 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2223 _("Transference of %s was cancelled."),
2224 tny_folder_get_name (folder));
2227 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2230 /* Update state of new folder */
2232 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2233 tny_folder_poke_status (new_folder);
2236 /* Notify about operation end */
2237 modest_mail_operation_notify_end (self);
2239 /* If user defined callback function was defined, call it */
2240 if (helper->user_callback) {
2242 /* This is not a GDK lock because we are a Tinymail callback
2243 * which is already GDK locked by Tinymail */
2245 /* no gdk_threads_enter (), CHECKED */
2246 helper->user_callback (self, new_folder, helper->user_data);
2247 /* no gdk_threads_leave () , CHECKED */
2251 g_object_unref (helper->mail_op);
2252 g_slice_free (XFerFolderAsyncHelper, helper);
2257 * This function checks if the new name is a valid name for our local
2258 * folders account. The new name could not be the same than then name
2259 * of any of the mandatory local folders
2261 * We can not rely on tinymail because tinymail does not check the
2262 * name of the virtual folders that the account could have in the case
2263 * that we're doing a rename (because it directly calls Camel which
2264 * knows nothing about our virtual folders).
2266 * In the case of an actual copy/move (i.e. move/copy a folder between
2267 * accounts) tinymail uses the tny_folder_store_create_account which
2268 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2269 * checks the new name of the folder, so this call in that case
2270 * wouldn't be needed. *But* NOTE that if tinymail changes its
2271 * implementation (if folder transfers within the same account is no
2272 * longer implemented as a rename) this call will allow Modest to work
2275 * If the new name is not valid, this function will set the status to
2276 * failed and will set also an error in the mail operation
2279 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2280 TnyFolderStore *into,
2281 const gchar *new_name)
2283 if (TNY_IS_ACCOUNT (into) &&
2284 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2285 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2287 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2288 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2289 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2290 _CS("ckdg_ib_folder_already_exists"));
2297 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2299 TnyFolderStore *parent,
2300 gboolean delete_original,
2301 XferFolderAsyncUserCallback user_callback,
2304 ModestMailOperationPrivate *priv = NULL;
2305 ModestTnyFolderRules parent_rules = 0, rules;
2306 XFerFolderAsyncHelper *helper = NULL;
2307 const gchar *folder_name = NULL;
2308 const gchar *error_msg;
2310 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2311 g_return_if_fail (TNY_IS_FOLDER (folder));
2312 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2315 folder_name = tny_folder_get_name (folder);
2317 /* Set the error msg */
2318 error_msg = _("mail_in_ui_folder_move_target_error");
2320 /* Get account and set it into mail_operation */
2321 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2322 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2323 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2325 /* Get folder rules */
2326 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2327 if (TNY_IS_FOLDER (parent))
2328 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2330 /* Apply operation constraints */
2331 if ((gpointer) parent == (gpointer) folder ||
2332 (!TNY_IS_FOLDER_STORE (parent)) ||
2333 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2336 } else if (TNY_IS_FOLDER (parent) &&
2337 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2341 } else if (TNY_IS_FOLDER (parent) &&
2342 TNY_IS_FOLDER_STORE (folder) &&
2343 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2344 TNY_FOLDER_STORE (folder))) {
2345 /* Do not move a parent into a child */
2347 } else if (TNY_IS_FOLDER_STORE (parent) &&
2348 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2349 /* Check that the new folder name is not used by any
2352 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2353 /* Check that the new folder name is not used by any
2354 special local folder */
2357 /* Create the helper */
2358 helper = g_slice_new0 (XFerFolderAsyncHelper);
2359 helper->mail_op = g_object_ref (self);
2360 helper->user_callback = user_callback;
2361 helper->user_data = user_data;
2363 /* Move/Copy folder */
2364 modest_mail_operation_notify_start (self);
2365 tny_folder_copy_async (folder,
2367 tny_folder_get_name (folder),
2370 transfer_folder_status_cb,
2376 /* Set status failed and set an error */
2377 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2378 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2379 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2382 /* Call the user callback if exists */
2384 user_callback (self, NULL, user_data);
2386 /* Notify the queue */
2387 modest_mail_operation_notify_end (self);
2391 modest_mail_operation_rename_folder (ModestMailOperation *self,
2394 XferFolderAsyncUserCallback user_callback,
2397 ModestMailOperationPrivate *priv;
2398 ModestTnyFolderRules rules;
2399 XFerFolderAsyncHelper *helper;
2401 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2402 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2403 g_return_if_fail (name);
2405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2407 /* Get account and set it into mail_operation */
2408 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2409 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2411 /* Check folder rules */
2412 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2413 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2415 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2418 TnyFolderStore *into;
2420 into = tny_folder_get_folder_store (folder);
2422 /* Check that the new folder name is not used by any
2423 special local folder */
2424 if (new_name_valid_if_local_account (priv, into, name)) {
2425 /* Create the helper */
2426 helper = g_slice_new0 (XFerFolderAsyncHelper);
2427 helper->mail_op = g_object_ref(self);
2428 helper->user_callback = user_callback;
2429 helper->user_data = user_data;
2431 /* Rename. Camel handles folder subscription/unsubscription */
2432 modest_mail_operation_notify_start (self);
2433 tny_folder_copy_async (folder, into, name, TRUE,
2435 transfer_folder_status_cb,
2437 g_object_unref (into);
2439 g_object_unref (into);
2446 /* Set status failed and set an error */
2447 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2448 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2449 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2450 _("FIXME: unable to rename"));
2453 user_callback (self, NULL, user_data);
2455 /* Notify about operation end */
2456 modest_mail_operation_notify_end (self);
2459 /* ******************************************************************* */
2460 /* ************************** MSG ACTIONS ************************* */
2461 /* ******************************************************************* */
2464 modest_mail_operation_get_msg (ModestMailOperation *self,
2466 gboolean progress_feedback,
2467 GetMsgAsyncUserCallback user_callback,
2470 GetMsgInfo *helper = NULL;
2472 ModestMailOperationPrivate *priv;
2474 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2475 g_return_if_fail (TNY_IS_HEADER (header));
2477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2478 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2482 /* Check memory low */
2483 if (_check_memory_low (self)) {
2485 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2486 modest_mail_operation_notify_end (self);
2490 /* Get account and set it into mail_operation */
2491 folder = tny_header_get_folder (header);
2492 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2494 /* Check for cached messages */
2495 if (progress_feedback) {
2496 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2497 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2499 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2501 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2504 /* Create the helper */
2505 helper = g_slice_new0 (GetMsgInfo);
2506 helper->header = g_object_ref (header);
2507 helper->mail_op = g_object_ref (self);
2508 helper->user_callback = user_callback;
2509 helper->user_data = user_data;
2510 helper->destroy_notify = NULL;
2511 helper->last_total_bytes = 0;
2512 helper->sum_total_bytes = 0;
2513 helper->total_bytes = tny_header_get_message_size (header);
2514 helper->more_msgs = NULL;
2516 modest_mail_operation_notify_start (self);
2518 /* notify about the start of the operation */
2519 ModestMailOperationState *state;
2520 state = modest_mail_operation_clone_state (self);
2523 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2525 g_slice_free (ModestMailOperationState, state);
2527 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2529 g_object_unref (G_OBJECT (folder));
2533 get_msg_status_cb (GObject *obj,
2537 GetMsgInfo *helper = NULL;
2539 g_return_if_fail (status != NULL);
2541 /* Show only the status information we want */
2542 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2545 helper = (GetMsgInfo *) user_data;
2546 g_return_if_fail (helper != NULL);
2548 /* Notify progress */
2549 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2550 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2554 get_msg_async_cb (TnyFolder *folder,
2560 GetMsgInfo *info = NULL;
2561 ModestMailOperationPrivate *priv = NULL;
2564 info = (GetMsgInfo *) user_data;
2566 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2569 if (info->more_msgs) {
2570 tny_iterator_next (info->more_msgs);
2571 finished = (tny_iterator_is_done (info->more_msgs));
2573 finished = (priv->done == priv->total) ? TRUE : FALSE;
2576 /* If canceled by the user, ignore the error given by Tinymail */
2580 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2582 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2584 priv->error = g_error_copy ((const GError *) err);
2585 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2588 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2589 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2592 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2593 /* Set the success status before calling the user callback */
2594 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2598 /* Call the user callback */
2599 if (info->user_callback)
2600 info->user_callback (info->mail_op, info->header, canceled,
2601 msg, err, info->user_data);
2603 /* Notify about operation end if this is the last callback */
2605 /* Free user data */
2606 if (info->destroy_notify)
2607 info->destroy_notify (info->user_data);
2609 /* Notify about operation end */
2610 modest_mail_operation_notify_end (info->mail_op);
2613 if (info->more_msgs)
2614 g_object_unref (info->more_msgs);
2615 g_object_unref (info->header);
2616 g_object_unref (info->mail_op);
2617 g_slice_free (GetMsgInfo, info);
2618 } else if (info->more_msgs) {
2619 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2620 TnyFolder *folder = tny_header_get_folder (header);
2622 g_object_unref (info->header);
2623 info->header = g_object_ref (header);
2625 /* Retrieve the next message */
2626 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2628 g_object_unref (header);
2629 g_object_unref (folder);
2631 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2636 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2637 TnyList *header_list,
2638 GetMsgAsyncUserCallback user_callback,
2640 GDestroyNotify notify)
2642 ModestMailOperationPrivate *priv = NULL;
2644 TnyIterator *iter = NULL;
2645 gboolean has_uncached_messages;
2647 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2649 /* Init mail operation */
2650 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2651 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2653 priv->total = tny_list_get_length(header_list);
2655 /* Check memory low */
2656 if (_check_memory_low (self)) {
2657 if (user_callback) {
2658 TnyHeader *header = NULL;
2661 if (tny_list_get_length (header_list) > 0) {
2662 iter = tny_list_create_iterator (header_list);
2663 header = (TnyHeader *) tny_iterator_get_current (iter);
2664 g_object_unref (iter);
2666 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2668 g_object_unref (header);
2672 /* Notify about operation end */
2673 modest_mail_operation_notify_end (self);
2677 /* Check uncached messages */
2678 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2679 !has_uncached_messages && !tny_iterator_is_done (iter);
2680 tny_iterator_next (iter)) {
2683 header = (TnyHeader *) tny_iterator_get_current (iter);
2684 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2685 has_uncached_messages = TRUE;
2686 g_object_unref (header);
2688 g_object_unref (iter);
2689 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2691 /* Get account and set it into mail_operation */
2692 if (tny_list_get_length (header_list) >= 1) {
2693 TnyIterator *iterator = tny_list_create_iterator (header_list);
2694 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2696 TnyFolder *folder = tny_header_get_folder (header);
2698 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2699 g_object_unref (folder);
2701 g_object_unref (header);
2703 g_object_unref (iterator);
2706 msg_list_size = compute_message_list_size (header_list, 0);
2708 modest_mail_operation_notify_start (self);
2709 iter = tny_list_create_iterator (header_list);
2710 if (!tny_iterator_is_done (iter)) {
2711 /* notify about the start of the operation */
2712 ModestMailOperationState *state;
2713 state = modest_mail_operation_clone_state (self);
2716 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2719 GetMsgInfo *msg_info = NULL;
2720 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2721 TnyFolder *folder = tny_header_get_folder (header);
2723 /* Create the message info */
2724 msg_info = g_slice_new0 (GetMsgInfo);
2725 msg_info->mail_op = g_object_ref (self);
2726 msg_info->header = g_object_ref (header);
2727 msg_info->more_msgs = g_object_ref (iter);
2728 msg_info->user_callback = user_callback;
2729 msg_info->user_data = user_data;
2730 msg_info->destroy_notify = notify;
2731 msg_info->last_total_bytes = 0;
2732 msg_info->sum_total_bytes = 0;
2733 msg_info->total_bytes = msg_list_size;
2735 /* The callback will call it per each header */
2736 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2738 /* Free and go on */
2739 g_object_unref (header);
2740 g_object_unref (folder);
2741 g_slice_free (ModestMailOperationState, state);
2743 g_object_unref (iter);
2748 remove_msgs_async_cb (TnyFolder *folder,
2753 gboolean expunge, leave_on_server;
2754 const gchar *account_name;
2755 TnyAccount *account;
2756 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2757 ModestMailOperation *self;
2758 ModestMailOperationPrivate *priv;
2759 ModestProtocolRegistry *protocol_registry;
2761 self = (ModestMailOperation *) user_data;
2762 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2763 protocol_registry = modest_runtime_get_protocol_registry ();
2765 if (canceled || err) {
2766 /* If canceled by the user, ignore the error given by Tinymail */
2768 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2770 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2771 priv->error = g_error_copy ((const GError *) err);
2772 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2775 modest_mail_operation_notify_end (self);
2776 g_object_unref (self);
2780 account = tny_folder_get_account (folder);
2781 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2783 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2785 account_proto = modest_tny_account_get_protocol_type (account);
2786 g_object_unref (account);
2788 if ((modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) &&
2789 !leave_on_server) ||
2790 !modest_tny_folder_is_remote_folder (folder))
2796 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2801 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2803 gboolean remove_to_trash /*ignored*/)
2805 TnyFolder *folder = NULL;
2806 ModestMailOperationPrivate *priv;
2807 TnyIterator *iter = NULL;
2808 TnyHeader *header = NULL;
2809 TnyList *remove_headers = NULL;
2810 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2812 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2813 g_return_if_fail (TNY_IS_LIST (headers));
2815 if (remove_to_trash)
2816 g_warning ("remove to trash is not implemented");
2818 if (tny_list_get_length(headers) == 0) {
2819 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2820 goto cleanup; /* nothing to do */
2823 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2824 remove_headers = g_object_ref(headers);
2826 /* Get folder from first header and sync it */
2827 iter = tny_list_create_iterator (headers);
2828 header = TNY_HEADER (tny_iterator_get_current (iter));
2830 folder = tny_header_get_folder (header);
2831 if (!TNY_IS_FOLDER(folder)) {
2832 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2836 /* Don't remove messages that are being sent */
2837 if (modest_tny_folder_is_local_folder (folder)) {
2838 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2840 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2841 TnyTransportAccount *traccount = NULL;
2842 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2843 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2845 ModestTnySendQueueStatus status;
2846 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2848 if (TNY_IS_SEND_QUEUE (send_queue)) {
2849 TnyIterator *iter = tny_list_create_iterator(headers);
2850 g_object_unref(remove_headers);
2851 remove_headers = TNY_LIST(tny_simple_list_new());
2852 while (!tny_iterator_is_done(iter)) {
2854 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2855 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2856 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2857 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2858 tny_list_append(remove_headers, G_OBJECT(hdr));
2860 g_object_unref(hdr);
2862 tny_iterator_next(iter);
2864 g_object_unref(iter);
2866 g_object_unref(traccount);
2870 /* Get account and set it into mail_operation */
2871 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2872 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2873 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2875 /* remove message from folder */
2876 modest_mail_operation_notify_start (self);
2877 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2878 NULL, g_object_ref (self));
2882 g_object_unref (remove_headers);
2884 g_object_unref (header);
2886 g_object_unref (iter);
2888 g_object_unref (folder);
2892 notify_progress_of_multiple_messages (ModestMailOperation *self,
2894 gint *last_total_bytes,
2895 gint *sum_total_bytes,
2897 gboolean increment_done)
2899 ModestMailOperationPrivate *priv;
2900 ModestMailOperationState *state;
2901 gboolean is_num_bytes = FALSE;
2903 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2905 /* We know that tinymail sends us information about
2906 * transferred bytes with this particular message
2908 if (status->message)
2909 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2911 state = modest_mail_operation_clone_state (self);
2912 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2913 /* We know that we're in a different message when the
2914 total number of bytes to transfer is different. Of
2915 course it could fail if we're transferring messages
2916 of the same size, but this is a workarround */
2917 if (status->of_total != *last_total_bytes) {
2918 /* We need to increment the done when there is
2919 no information about each individual
2920 message, we need to do this in message
2921 transfers, and we don't do it for getting
2925 *sum_total_bytes += *last_total_bytes;
2926 *last_total_bytes = status->of_total;
2928 state->bytes_done += status->position + *sum_total_bytes;
2929 state->bytes_total = total_bytes;
2931 /* Notify the status change. Only notify about changes
2932 referred to bytes */
2933 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2937 g_slice_free (ModestMailOperationState, state);
2941 transfer_msgs_status_cb (GObject *obj,
2945 XFerMsgsAsyncHelper *helper;
2947 g_return_if_fail (status != NULL);
2949 /* Show only the status information we want */
2950 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2953 helper = (XFerMsgsAsyncHelper *) user_data;
2954 g_return_if_fail (helper != NULL);
2956 /* Notify progress */
2957 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2958 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2962 transfer_msgs_sync_folder_cb (TnyFolder *self,
2967 XFerMsgsAsyncHelper *helper;
2968 /* We don't care here about the results of the
2970 helper = (XFerMsgsAsyncHelper *) user_data;
2972 /* Notify about operation end */
2973 modest_mail_operation_notify_end (helper->mail_op);
2975 /* If user defined callback function was defined, call it */
2976 if (helper->user_callback)
2977 helper->user_callback (helper->mail_op, helper->user_data);
2980 if (helper->more_msgs)
2981 g_object_unref (helper->more_msgs);
2982 if (helper->headers)
2983 g_object_unref (helper->headers);
2984 if (helper->dest_folder)
2985 g_object_unref (helper->dest_folder);
2986 if (helper->mail_op)
2987 g_object_unref (helper->mail_op);
2988 g_slice_free (XFerMsgsAsyncHelper, helper);
2992 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2994 XFerMsgsAsyncHelper *helper;
2995 ModestMailOperation *self;
2996 ModestMailOperationPrivate *priv;
2997 gboolean finished = TRUE;
2999 helper = (XFerMsgsAsyncHelper *) user_data;
3000 self = helper->mail_op;
3002 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3005 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3007 priv->error = g_error_copy (err);
3009 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3010 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3011 if (helper->more_msgs) {
3012 /* We'll transfer the next message in the list */
3013 tny_iterator_next (helper->more_msgs);
3014 if (!tny_iterator_is_done (helper->more_msgs)) {
3015 GObject *next_header;
3016 g_object_unref (helper->headers);
3017 helper->headers = tny_simple_list_new ();
3018 next_header = tny_iterator_get_current (helper->more_msgs);
3019 tny_list_append (helper->headers, next_header);
3020 g_object_unref (next_header);
3026 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3031 /* Synchronize the source folder contents. This should
3032 be done by tinymail but the camel_folder_sync it's
3033 actually disabled in transfer_msgs_thread_clean
3034 because it's supposed to cause hangs */
3035 tny_folder_sync_async (folder, helper->delete,
3036 transfer_msgs_sync_folder_cb,
3039 /* Transfer more messages */
3040 tny_folder_transfer_msgs_async (folder,
3042 helper->dest_folder,
3045 transfer_msgs_status_cb,
3050 /* Computes the size of the messages the headers in the list belongs
3051 to. If num_elements is different from 0 then it only takes into
3052 account the first num_elements for the calculation */
3054 compute_message_list_size (TnyList *headers,
3058 guint size = 0, element = 0;
3060 /* If num_elements is not valid then take all into account */
3061 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3062 num_elements = tny_list_get_length (headers);
3064 iter = tny_list_create_iterator (headers);
3065 while (!tny_iterator_is_done (iter) && element < num_elements) {
3066 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3067 size += tny_header_get_message_size (header);
3068 g_object_unref (header);
3069 tny_iterator_next (iter);
3072 g_object_unref (iter);
3078 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3081 gboolean delete_original,
3082 XferMsgsAsyncUserCallback user_callback,
3085 ModestMailOperationPrivate *priv = NULL;
3086 TnyIterator *iter = NULL;
3087 TnyFolder *src_folder = NULL;
3088 XFerMsgsAsyncHelper *helper = NULL;
3089 TnyHeader *header = NULL;
3090 ModestTnyFolderRules rules = 0;
3091 TnyAccount *dst_account = NULL;
3092 gboolean leave_on_server;
3093 ModestMailOperationState *state;
3094 ModestProtocolRegistry *protocol_registry;
3095 ModestProtocolType account_protocol;
3097 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3098 g_return_if_fail (headers && TNY_IS_LIST (headers));
3099 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3101 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3102 protocol_registry = modest_runtime_get_protocol_registry ();
3104 priv->total = tny_list_get_length (headers);
3106 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3107 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3109 /* Apply folder rules */
3110 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3111 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3112 /* Set status failed and set an error */
3113 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3114 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3115 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3116 _CS("ckct_ib_unable_to_paste_here"));
3117 /* Notify the queue */
3118 modest_mail_operation_notify_end (self);
3122 /* Get source folder */
3123 iter = tny_list_create_iterator (headers);
3124 header = TNY_HEADER (tny_iterator_get_current (iter));
3126 src_folder = tny_header_get_folder (header);
3127 g_object_unref (header);
3129 g_object_unref (iter);
3131 if (src_folder == NULL) {
3132 /* Notify the queue */
3133 modest_mail_operation_notify_end (self);
3135 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3140 /* Check folder source and destination */
3141 if (src_folder == folder) {
3142 /* Set status failed and set an error */
3143 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3144 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3145 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3146 _("mail_in_ui_folder_copy_target_error"));
3148 /* Notify the queue */
3149 modest_mail_operation_notify_end (self);
3152 g_object_unref (src_folder);
3156 /* Create the helper */
3157 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3158 helper->mail_op = g_object_ref(self);
3159 helper->dest_folder = g_object_ref(folder);
3160 helper->user_callback = user_callback;
3161 helper->user_data = user_data;
3162 helper->last_total_bytes = 0;
3163 helper->sum_total_bytes = 0;
3164 helper->total_bytes = compute_message_list_size (headers, 0);
3166 /* Get account and set it into mail_operation */
3167 priv->account = modest_tny_folder_get_account (src_folder);
3168 dst_account = modest_tny_folder_get_account (folder);
3170 if (priv->account == dst_account) {
3171 /* Transfer all messages at once using the fast
3172 * method. Note that depending on the server this
3173 * might not be that fast, and might not be
3174 * user-cancellable either */
3175 helper->headers = g_object_ref (headers);
3176 helper->more_msgs = NULL;
3178 /* Transfer messages one by one so the user can cancel
3181 helper->headers = tny_simple_list_new ();
3182 helper->more_msgs = tny_list_create_iterator (headers);
3183 hdr = tny_iterator_get_current (helper->more_msgs);
3184 tny_list_append (helper->headers, hdr);
3185 g_object_unref (hdr);
3188 /* If leave_on_server is set to TRUE then don't use
3189 delete_original, we always pass FALSE. This is because
3190 otherwise tinymail will try to sync the source folder and
3191 this could cause an error if we're offline while
3192 transferring an already downloaded message from a POP
3194 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3195 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3196 const gchar *account_name;
3198 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3199 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3202 leave_on_server = FALSE;
3205 /* Do not delete messages if leave on server is TRUE */
3206 helper->delete = (leave_on_server) ? FALSE : delete_original;
3208 modest_mail_operation_notify_start (self);
3210 /* Start notifying progress */
3211 state = modest_mail_operation_clone_state (self);
3214 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3215 g_slice_free (ModestMailOperationState, state);
3217 tny_folder_transfer_msgs_async (src_folder,
3222 transfer_msgs_status_cb,
3224 g_object_unref (src_folder);
3225 g_object_unref (dst_account);
3230 on_refresh_folder (TnyFolder *folder,
3235 RefreshAsyncHelper *helper = NULL;
3236 ModestMailOperation *self = NULL;
3237 ModestMailOperationPrivate *priv = NULL;
3239 helper = (RefreshAsyncHelper *) user_data;
3240 self = helper->mail_op;
3241 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3243 g_return_if_fail(priv!=NULL);
3246 priv->error = g_error_copy (error);
3247 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3252 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3253 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3254 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3255 _("Error trying to refresh the contents of %s"),
3256 tny_folder_get_name (folder));
3260 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3263 /* Call user defined callback, if it exists */
3264 if (helper->user_callback) {
3266 /* This is not a GDK lock because we are a Tinymail callback and
3267 * Tinymail already acquires the Gdk lock */
3268 helper->user_callback (self, folder, helper->user_data);
3272 g_slice_free (RefreshAsyncHelper, helper);
3274 /* Notify about operation end */
3275 modest_mail_operation_notify_end (self);
3276 g_object_unref(self);
3280 on_refresh_folder_status_update (GObject *obj,
3284 RefreshAsyncHelper *helper = NULL;
3285 ModestMailOperation *self = NULL;
3286 ModestMailOperationPrivate *priv = NULL;
3287 ModestMailOperationState *state;
3289 g_return_if_fail (user_data != NULL);
3290 g_return_if_fail (status != NULL);
3292 /* Show only the status information we want */
3293 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3296 helper = (RefreshAsyncHelper *) user_data;
3297 self = helper->mail_op;
3298 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3300 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3302 priv->done = status->position;
3303 priv->total = status->of_total;
3305 state = modest_mail_operation_clone_state (self);
3307 /* This is not a GDK lock because we are a Tinymail callback and
3308 * Tinymail already acquires the Gdk lock */
3309 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3311 g_slice_free (ModestMailOperationState, state);
3315 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3317 RefreshAsyncUserCallback user_callback,
3320 ModestMailOperationPrivate *priv = NULL;
3321 RefreshAsyncHelper *helper = NULL;
3323 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3325 /* Check memory low */
3326 if (_check_memory_low (self)) {
3328 user_callback (self, folder, user_data);
3329 /* Notify about operation end */
3330 modest_mail_operation_notify_end (self);
3334 /* Get account and set it into mail_operation */
3335 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3336 priv->account = modest_tny_folder_get_account (folder);
3337 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3339 /* Create the helper */
3340 helper = g_slice_new0 (RefreshAsyncHelper);
3341 helper->mail_op = g_object_ref(self);
3342 helper->user_callback = user_callback;
3343 helper->user_data = user_data;
3345 modest_mail_operation_notify_start (self);
3347 /* notify that the operation was started */
3348 ModestMailOperationState *state;
3349 state = modest_mail_operation_clone_state (self);
3352 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3354 g_slice_free (ModestMailOperationState, state);
3356 tny_folder_refresh_async (folder,
3358 on_refresh_folder_status_update,
3363 run_queue_notify_and_destroy (RunQueueHelper *helper,
3364 ModestMailOperationStatus status)
3366 ModestMailOperationPrivate *priv;
3369 if (helper->error_handler &&
3370 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3371 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3372 if (helper->start_handler &&
3373 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3374 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3375 if (helper->stop_handler &&
3376 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3377 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3380 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3381 priv->status = status;
3384 modest_mail_operation_notify_end (helper->self);
3387 g_object_unref (helper->queue);
3388 g_object_unref (helper->self);
3389 g_slice_free (RunQueueHelper, helper);
3393 run_queue_stop (ModestTnySendQueue *queue,
3396 RunQueueHelper *helper;
3398 g_debug ("%s sending queue stopped", __FUNCTION__);
3400 helper = (RunQueueHelper *) user_data;
3401 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3405 modest_mail_operation_run_queue (ModestMailOperation *self,
3406 ModestTnySendQueue *queue)
3408 ModestMailOperationPrivate *priv;
3409 RunQueueHelper *helper;
3411 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3412 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3413 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3415 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3416 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3417 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3419 /* Create the helper */
3420 helper = g_slice_new0 (RunQueueHelper);
3421 helper->queue = g_object_ref (queue);
3422 helper->self = g_object_ref (self);
3423 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3424 G_CALLBACK (run_queue_stop),
3427 /* Notify operation has started */
3428 modest_mail_operation_notify_start (self);
3429 g_debug ("%s, run queue started", __FUNCTION__);
3433 queue_wakeup_callback (ModestTnySendQueue *queue,
3438 ModestMailOperation *mail_op;
3439 ModestMailOperationPrivate *priv;
3441 mail_op = (ModestMailOperation *) userdata;
3442 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3444 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3445 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3448 modest_mail_operation_notify_end (mail_op);
3449 g_object_unref (mail_op);
3453 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3454 ModestTnySendQueue *queue)
3456 ModestMailOperationPrivate *priv;
3458 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3459 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3462 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3463 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3464 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3466 g_object_ref (self);
3468 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3469 modest_mail_operation_notify_start (self);
3473 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3475 ModestMailOperation *self = (ModestMailOperation *) userdata;
3476 ModestMailOperationPrivate *priv;
3478 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3479 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3482 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3484 modest_mail_operation_notify_end (self);
3485 g_object_unref (self);
3489 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3491 ModestMailOperationPrivate *priv;
3493 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3494 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3495 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3497 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3499 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3500 priv->account = NULL;
3501 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3503 modest_mail_operation_notify_start (self);
3504 g_object_ref (self);
3505 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3509 sync_folder_finish_callback (TnyFolder *self,
3515 ModestMailOperation *mail_op;
3516 ModestMailOperationPrivate *priv;
3518 mail_op = (ModestMailOperation *) user_data;
3519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3521 /* If canceled by the user, ignore the error given by Tinymail */
3523 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3525 /* If the operation was a sync then the status is
3526 failed, but if it's part of another operation then
3527 just set it as finished with errors */
3528 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3529 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3531 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3532 priv->error = g_error_copy ((const GError *) err);
3533 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3535 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3538 modest_mail_operation_notify_end (mail_op);
3539 g_object_unref (mail_op);
3543 modest_mail_operation_sync_folder (ModestMailOperation *self,
3544 TnyFolder *folder, gboolean expunge)
3546 ModestMailOperationPrivate *priv;
3548 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3549 g_return_if_fail (TNY_IS_FOLDER (folder));
3550 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3552 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3553 priv->account = modest_tny_folder_get_account (folder);
3554 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3556 modest_mail_operation_notify_start (self);
3557 g_object_ref (self);
3558 tny_folder_sync_async (folder, expunge,
3559 (TnyFolderCallback) sync_folder_finish_callback,
3564 modest_mail_operation_notify_start (ModestMailOperation *self)
3566 ModestMailOperationPrivate *priv = NULL;
3568 g_return_if_fail (self);
3570 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3572 /* Ensure that all the fields are filled correctly */
3573 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3575 /* Notify the observers about the mail operation. We do not
3576 wrapp this emission because we assume that this function is
3577 always called from within the main lock */
3578 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3583 * It's used by the mail operation queue to notify the observers
3584 * attached to that signal that the operation finished. We need to use
3585 * that because tinymail does not give us the progress of a given
3586 * operation when it finishes (it directly calls the operation
3590 modest_mail_operation_notify_end (ModestMailOperation *self)
3592 ModestMailOperationPrivate *priv = NULL;
3594 g_return_if_fail (self);
3596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3598 /* Notify the observers about the mail operation end. We do
3599 not wrapp this emission because we assume that this
3600 function is always called from within the main lock */
3601 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3603 /* Remove the error user data */
3604 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3605 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3609 modest_mail_operation_get_account (ModestMailOperation *self)
3611 ModestMailOperationPrivate *priv = NULL;
3613 g_return_val_if_fail (self, NULL);
3615 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3617 return (priv->account) ? g_object_ref (priv->account) : NULL;
3621 modest_mail_operation_noop (ModestMailOperation *self)
3623 ModestMailOperationPrivate *priv = NULL;
3625 g_return_if_fail (self);
3627 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3628 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3629 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3633 /* This mail operation does nothing actually */
3634 modest_mail_operation_notify_start (self);
3635 modest_mail_operation_notify_end (self);
3640 modest_mail_operation_to_string (ModestMailOperation *self)
3642 const gchar *type, *status, *account_id;
3643 ModestMailOperationPrivate *priv = NULL;
3645 g_return_val_if_fail (self, NULL);
3647 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3649 /* new operations don't have anything interesting */
3650 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3651 return g_strdup_printf ("%p <new operation>", self);
3653 switch (priv->op_type) {
3654 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3655 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3656 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3657 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3658 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3659 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3660 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3661 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3662 default: type = "UNEXPECTED"; break;
3665 switch (priv->status) {
3666 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3667 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3668 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3669 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3670 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3671 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3672 default: status= "UNEXPECTED"; break;
3675 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3677 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3678 priv->done, priv->total,
3679 priv->error && priv->error->message ? priv->error->message : "");
3683 * Once the mail operations were objects this will be no longer
3684 * needed. I don't like it, but we need it for the moment
3687 _check_memory_low (ModestMailOperation *mail_op)
3689 if (modest_platform_check_memory_low (NULL, FALSE)) {
3690 ModestMailOperationPrivate *priv;
3692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3693 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3694 g_set_error (&(priv->error),
3695 MODEST_MAIL_OPERATION_ERROR,
3696 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3697 "Not enough memory to complete the operation");