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) {
1235 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1236 cb_info->transport_account = g_object_ref(info->transport_account);
1237 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1238 cb_info->callback = info->callback;
1239 cb_info->user_data = info->user_data;
1240 cb_info->drafts = g_object_ref(drafts);
1241 cb_info->msg = g_object_ref(msg);
1242 cb_info->mailop = g_object_ref(self);
1243 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1246 /* Call the user callback */
1247 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1249 info->callback (self, msg, info->user_data);
1250 modest_mail_operation_notify_end (self);
1254 g_object_unref (G_OBJECT(drafts));
1255 if (info->draft_msg)
1256 g_object_unref (G_OBJECT (info->draft_msg));
1257 if (info->transport_account)
1258 g_object_unref (G_OBJECT(info->transport_account));
1259 g_slice_free (SaveToDraftsInfo, info);
1263 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1264 TnyTransportAccount *transport_account,
1266 const gchar *from, const gchar *to,
1267 const gchar *cc, const gchar *bcc,
1268 const gchar *subject, const gchar *plain_body,
1269 const gchar *html_body,
1270 const GList *attachments_list,
1271 const GList *images_list,
1272 TnyHeaderFlags priority_flags,
1273 SaveToDraftstCallback callback,
1276 ModestMailOperationPrivate *priv = NULL;
1277 SaveToDraftsInfo *info = NULL;
1279 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1280 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1282 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1284 /* Get account and set it into mail_operation */
1285 priv->account = g_object_ref (transport_account);
1286 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1288 info = g_slice_new0 (SaveToDraftsInfo);
1289 info->transport_account = g_object_ref (transport_account);
1290 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1291 info->callback = callback;
1292 info->user_data = user_data;
1294 g_debug ("--- CREATE MESSAGE");
1295 modest_mail_operation_notify_start (self);
1296 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1297 attachments_list, images_list, priority_flags,
1298 modest_mail_operation_save_to_drafts_cb, info);
1303 ModestMailOperation *mail_op;
1304 TnyMimePart *mime_part;
1306 GetMimePartSizeCallback callback;
1308 } GetMimePartSizeInfo;
1310 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1311 /* We use this folder observer to track the headers that have been
1312 * added to a folder */
1315 TnyList *new_headers;
1316 } InternalFolderObserver;
1319 GObjectClass parent;
1320 } InternalFolderObserverClass;
1322 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1324 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1325 internal_folder_observer,
1327 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1331 foreach_add_item (gpointer header, gpointer user_data)
1333 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1336 /* This is the method that looks for new messages in a folder */
1338 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1340 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1342 TnyFolderChangeChanged changed;
1344 changed = tny_folder_change_get_changed (change);
1346 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1349 /* Get added headers */
1350 list = tny_simple_list_new ();
1351 tny_folder_change_get_added_headers (change, list);
1353 /* Add them to the folder observer */
1354 tny_list_foreach (list, foreach_add_item,
1355 derived->new_headers);
1357 g_object_unref (G_OBJECT (list));
1362 internal_folder_observer_init (InternalFolderObserver *self)
1364 self->new_headers = tny_simple_list_new ();
1367 internal_folder_observer_finalize (GObject *object)
1369 InternalFolderObserver *self;
1371 self = (InternalFolderObserver *) object;
1372 g_object_unref (self->new_headers);
1374 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1377 tny_folder_observer_init (TnyFolderObserverIface *iface)
1379 iface->update = internal_folder_observer_update;
1382 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1384 GObjectClass *object_class;
1386 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1387 object_class = (GObjectClass*) klass;
1388 object_class->finalize = internal_folder_observer_finalize;
1392 destroy_update_account_info (UpdateAccountInfo *info)
1394 g_free (info->account_name);
1395 g_object_unref (info->folders);
1396 g_object_unref (info->mail_op);
1397 g_slice_free (UpdateAccountInfo, info);
1402 update_account_send_mail (UpdateAccountInfo *info)
1404 TnyTransportAccount *transport_account = NULL;
1405 ModestTnyAccountStore *account_store;
1407 account_store = modest_runtime_get_account_store ();
1409 /* We don't try to send messages while sending mails is blocked */
1410 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1413 /* Get the transport account */
1414 transport_account = (TnyTransportAccount *)
1415 modest_tny_account_store_get_server_account (account_store, info->account_name,
1416 TNY_ACCOUNT_TYPE_TRANSPORT);
1418 if (transport_account) {
1419 ModestTnySendQueue *send_queue;
1423 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1424 g_object_unref (transport_account);
1426 if (TNY_IS_SEND_QUEUE (send_queue)) {
1427 /* Get outbox folder */
1428 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1429 if (outbox) { /* this could fail in some cases */
1430 num_messages = tny_folder_get_all_count (outbox);
1431 g_object_unref (outbox);
1433 g_warning ("%s: could not get outbox", __FUNCTION__);
1437 if (num_messages != 0) {
1438 ModestMailOperation *mail_op;
1439 /* Reenable suspended items */
1440 mail_op = modest_mail_operation_new (NULL);
1441 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1443 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1446 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1454 update_account_get_msg_async_cb (TnyFolder *folder,
1460 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1461 ModestMailOperationPrivate *priv;
1463 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1466 if (TNY_IS_MSG (msg)) {
1467 TnyHeader *header = tny_msg_get_header (msg);
1470 ModestMailOperationState *state;
1471 state = modest_mail_operation_clone_state (msg_info->mail_op);
1472 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1473 state->bytes_done = msg_info->sum_total_bytes;
1474 state->bytes_total = msg_info->total_bytes;
1476 /* Notify the status change. Only notify about changes
1477 referred to bytes */
1478 g_signal_emit (G_OBJECT (msg_info->mail_op),
1479 signals[PROGRESS_CHANGED_SIGNAL],
1482 g_object_unref (header);
1483 g_slice_free (ModestMailOperationState, state);
1487 if (priv->done == priv->total) {
1488 TnyList *new_headers;
1489 UpdateAccountInfo *info;
1491 /* After getting all the messages send the ones in the
1493 info = (UpdateAccountInfo *) msg_info->user_data;
1494 update_account_send_mail (info);
1496 /* Check if the operation was a success */
1498 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1500 /* Call the user callback and free */
1501 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1502 update_account_notify_user_and_free (info, new_headers);
1503 g_object_unref (new_headers);
1505 /* Delete the helper */
1506 g_object_unref (msg_info->more_msgs);
1507 g_object_unref (msg_info->mail_op);
1508 g_slice_free (GetMsgInfo, msg_info);
1513 update_account_notify_user_and_free (UpdateAccountInfo *info,
1514 TnyList *new_headers)
1516 /* Set the account back to not busy */
1517 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1518 info->account_name, FALSE);
1522 info->callback (info->mail_op, new_headers, info->user_data);
1524 /* Mail operation end */
1525 modest_mail_operation_notify_end (info->mail_op);
1529 g_object_unref (new_headers);
1530 destroy_update_account_info (info);
1534 inbox_refreshed_cb (TnyFolder *inbox,
1539 UpdateAccountInfo *info;
1540 ModestMailOperationPrivate *priv;
1541 TnyIterator *new_headers_iter;
1542 GPtrArray *new_headers_array = NULL;
1543 gint max_size, retrieve_limit, i;
1544 ModestAccountMgr *mgr;
1545 ModestAccountRetrieveType retrieve_type;
1546 TnyList *new_headers = NULL;
1547 gboolean headers_only, ignore_limit;
1549 info = (UpdateAccountInfo *) user_data;
1550 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1551 mgr = modest_runtime_get_account_mgr ();
1553 if (canceled || err) {
1554 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1556 priv->error = g_error_copy (err);
1558 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1559 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1562 tny_folder_remove_observer (inbox, info->inbox_observer);
1563 g_object_unref (info->inbox_observer);
1564 info->inbox_observer = NULL;
1566 /* Notify the user about the error and then exit */
1567 update_account_notify_user_and_free (info, NULL);
1572 /* Try to send anyway */
1576 /* Set the last updated as the current time */
1577 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1579 /* Get the message max size */
1580 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1581 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1583 max_size = G_MAXINT;
1585 max_size = max_size * KB;
1587 /* Create the new headers array. We need it to sort the
1588 new headers by date */
1589 new_headers_array = g_ptr_array_new ();
1590 if (info->inbox_observer) {
1591 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1592 while (!tny_iterator_is_done (new_headers_iter)) {
1593 TnyHeader *header = NULL;
1595 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1596 /* Apply per-message size limits */
1597 if (tny_header_get_message_size (header) < max_size)
1598 g_ptr_array_add (new_headers_array, g_object_ref (header));
1600 g_object_unref (header);
1601 tny_iterator_next (new_headers_iter);
1603 g_object_unref (new_headers_iter);
1605 tny_folder_remove_observer (inbox, info->inbox_observer);
1606 g_object_unref (info->inbox_observer);
1607 info->inbox_observer = NULL;
1610 if (new_headers_array->len == 0) {
1611 g_ptr_array_free (new_headers_array, FALSE);
1615 /* Get per-account message amount retrieval limit */
1616 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1617 if (retrieve_limit == 0)
1618 retrieve_limit = G_MAXINT;
1620 /* Get per-account retrieval type */
1621 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1622 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1625 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1627 /* Ask the users if they want to retrieve all the messages
1628 even though the limit was exceeded */
1629 ignore_limit = FALSE;
1630 if (new_headers_array->len > retrieve_limit) {
1631 /* Ask the user if a callback has been specified and
1632 if the mail operation has a source (this means that
1633 was invoked by the user and not automatically by a
1635 if (info->retrieve_all_cb && priv->source)
1636 ignore_limit = info->retrieve_all_cb (priv->source,
1637 new_headers_array->len,
1641 /* Copy the headers to a list and free the array */
1642 new_headers = tny_simple_list_new ();
1643 for (i=0; i < new_headers_array->len; i++) {
1644 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1645 tny_list_append (new_headers, G_OBJECT (header));
1647 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1648 g_ptr_array_free (new_headers_array, FALSE);
1650 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1653 GetMsgInfo *msg_info;
1657 priv->total = tny_list_get_length (new_headers);
1659 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1661 iter = tny_list_create_iterator (new_headers);
1663 /* Create the message info */
1664 msg_info = g_slice_new0 (GetMsgInfo);
1665 msg_info->mail_op = g_object_ref (info->mail_op);
1666 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1667 msg_info->more_msgs = g_object_ref (iter);
1668 msg_info->user_data = info;
1670 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1671 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1672 TnyFolder *folder = tny_header_get_folder (header);
1674 /* Get message in an async way */
1675 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1678 g_object_unref (folder);
1681 tny_iterator_next (iter);
1683 g_object_unref (iter);
1685 /* The mail operation will finish when the last
1686 message is retrieved */
1690 /* If we don't have to retrieve the new messages then
1692 update_account_send_mail (info);
1694 /* Check if the operation was a success */
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1698 /* Call the user callback and free */
1699 update_account_notify_user_and_free (info, new_headers);
1703 inbox_refresh_status_update (GObject *obj,
1707 UpdateAccountInfo *info = NULL;
1708 ModestMailOperation *self = NULL;
1709 ModestMailOperationPrivate *priv = NULL;
1710 ModestMailOperationState *state;
1712 g_return_if_fail (user_data != NULL);
1713 g_return_if_fail (status != NULL);
1715 /* Show only the status information we want */
1716 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1719 info = (UpdateAccountInfo *) user_data;
1720 self = info->mail_op;
1721 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1723 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1725 priv->done = status->position;
1726 priv->total = status->of_total;
1728 state = modest_mail_operation_clone_state (self);
1730 /* This is not a GDK lock because we are a Tinymail callback and
1731 * Tinymail already acquires the Gdk lock */
1732 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1734 g_slice_free (ModestMailOperationState, state);
1738 recurse_folders_async_cb (TnyFolderStore *folder_store,
1744 UpdateAccountInfo *info;
1745 ModestMailOperationPrivate *priv;
1747 info = (UpdateAccountInfo *) user_data;
1748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1750 if (err || canceled) {
1751 /* If the error was previosly set by another callback
1752 don't set it again */
1754 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1756 priv->error = g_error_copy (err);
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1763 /* We're not getting INBOX children if we don't want to poke all */
1764 TnyIterator *iter = tny_list_create_iterator (list);
1765 while (!tny_iterator_is_done (iter)) {
1766 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1768 /* Add to the list of all folders */
1769 tny_list_append (info->folders, (GObject *) folder);
1771 if (info->poke_all) {
1772 TnyList *folders = tny_simple_list_new ();
1773 /* Add pending call */
1774 info->pending_calls++;
1776 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1777 recurse_folders_async_cb,
1779 g_object_unref (folders);
1782 g_object_unref (G_OBJECT (folder));
1784 tny_iterator_next (iter);
1786 g_object_unref (G_OBJECT (iter));
1789 /* Remove my own pending call */
1790 info->pending_calls--;
1792 /* This means that we have all the folders */
1793 if (info->pending_calls == 0) {
1794 TnyIterator *iter_all_folders;
1795 TnyFolder *inbox = NULL;
1797 /* If there was any error do not continue */
1799 update_account_notify_user_and_free (info, NULL);
1803 iter_all_folders = tny_list_create_iterator (info->folders);
1805 /* Do a poke status over all folders */
1806 while (!tny_iterator_is_done (iter_all_folders) &&
1807 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1808 TnyFolder *folder = NULL;
1810 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1812 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1813 /* Get a reference to the INBOX */
1814 inbox = g_object_ref (folder);
1816 /* Issue a poke status over the folder */
1818 tny_folder_poke_status (folder);
1821 /* Free and go to next */
1822 g_object_unref (folder);
1823 tny_iterator_next (iter_all_folders);
1825 g_object_unref (iter_all_folders);
1827 /* Refresh the INBOX */
1829 /* Refresh the folder. Our observer receives
1830 * the new emails during folder refreshes, so
1831 * we can use observer->new_headers
1833 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1834 tny_folder_add_observer (inbox, info->inbox_observer);
1836 /* Refresh the INBOX */
1837 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1838 g_object_unref (inbox);
1840 /* We could not perform the inbox refresh but
1841 we'll try to send mails anyway */
1842 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1848 modest_mail_operation_update_account (ModestMailOperation *self,
1849 const gchar *account_name,
1851 gboolean interactive,
1852 RetrieveAllCallback retrieve_all_cb,
1853 UpdateAccountCallback callback,
1856 UpdateAccountInfo *info = NULL;
1857 ModestMailOperationPrivate *priv = NULL;
1858 ModestTnyAccountStore *account_store = NULL;
1860 ModestMailOperationState *state;
1862 /* Init mail operation */
1863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1867 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1869 /* Get the store account */
1870 account_store = modest_runtime_get_account_store ();
1872 modest_tny_account_store_get_server_account (account_store,
1874 TNY_ACCOUNT_TYPE_STORE);
1876 /* The above function could return NULL */
1877 if (!priv->account) {
1878 /* Check if the operation was a success */
1879 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1880 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1882 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1884 /* Call the user callback */
1886 callback (self, NULL, user_data);
1888 /* Notify about operation end */
1889 modest_mail_operation_notify_end (self);
1894 /* We have once seen priv->account getting finalized during this code,
1895 * therefore adding a reference (bug #82296) */
1897 g_object_ref (priv->account);
1899 /* Create the helper object */
1900 info = g_slice_new0 (UpdateAccountInfo);
1901 info->pending_calls = 1;
1902 info->folders = tny_simple_list_new ();
1903 info->mail_op = g_object_ref (self);
1904 info->poke_all = poke_all;
1905 info->interactive = interactive;
1906 info->account_name = g_strdup (account_name);
1907 info->callback = callback;
1908 info->user_data = user_data;
1909 info->retrieve_all_cb = retrieve_all_cb;
1911 /* Set account busy */
1912 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1913 modest_mail_operation_notify_start (self);
1915 /* notify about the start of the operation */
1916 state = modest_mail_operation_clone_state (self);
1920 /* Start notifying progress */
1921 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1922 g_slice_free (ModestMailOperationState, state);
1924 /* Get all folders and continue in the callback */
1925 folders = tny_simple_list_new ();
1926 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1927 folders, NULL, FALSE,
1928 recurse_folders_async_cb,
1930 g_object_unref (folders);
1932 g_object_unref (priv->account);
1937 * Used to notify the queue from the main
1938 * loop. We call it inside an idle call to achieve that
1941 idle_notify_queue (gpointer data)
1943 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1945 gdk_threads_enter ();
1946 modest_mail_operation_notify_end (mail_op);
1947 gdk_threads_leave ();
1948 g_object_unref (mail_op);
1954 compare_headers_by_date (gconstpointer a,
1957 TnyHeader **header1, **header2;
1958 time_t sent1, sent2;
1960 header1 = (TnyHeader **) a;
1961 header2 = (TnyHeader **) b;
1963 sent1 = tny_header_get_date_sent (*header1);
1964 sent2 = tny_header_get_date_sent (*header2);
1966 /* We want the most recent ones (greater time_t) at the
1975 /* ******************************************************************* */
1976 /* ************************** STORE ACTIONS ************************* */
1977 /* ******************************************************************* */
1980 ModestMailOperation *mail_op;
1981 CreateFolderUserCallback callback;
1987 create_folder_cb (TnyFolderStore *parent_folder,
1989 TnyFolder *new_folder,
1993 ModestMailOperationPrivate *priv;
1994 CreateFolderInfo *info;
1996 info = (CreateFolderInfo *) user_data;
1997 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1999 if (canceled || err) {
2000 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2002 priv->error = g_error_copy (err);
2004 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2005 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2008 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2011 /* The user will unref the new_folder */
2013 info->callback (info->mail_op, parent_folder,
2014 new_folder, info->user_data);
2016 /* Notify about operation end */
2017 modest_mail_operation_notify_end (info->mail_op);
2020 g_object_unref (info->mail_op);
2021 g_slice_free (CreateFolderInfo, info);
2025 modest_mail_operation_create_folder (ModestMailOperation *self,
2026 TnyFolderStore *parent,
2028 CreateFolderUserCallback callback,
2031 ModestMailOperationPrivate *priv;
2033 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2034 g_return_if_fail (name);
2036 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2037 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2038 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2039 g_object_ref (parent) :
2040 modest_tny_folder_get_account (TNY_FOLDER (parent));
2042 /* Check for already existing folder */
2043 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2044 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2045 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2046 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2047 _CS("ckdg_ib_folder_already_exists"));
2051 if (TNY_IS_FOLDER (parent)) {
2052 /* Check folder rules */
2053 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2054 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2055 /* Set status failed and set an error */
2056 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2057 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2058 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2059 _("mail_in_ui_folder_create_error"));
2063 if (!strcmp (name, " ") || strchr (name, '/')) {
2064 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2065 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2066 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2067 _("mail_in_ui_folder_create_error"));
2071 CreateFolderInfo *info;
2073 info = g_slice_new0 (CreateFolderInfo);
2074 info->mail_op = g_object_ref (self);
2075 info->callback = callback;
2076 info->user_data = user_data;
2078 modest_mail_operation_notify_start (self);
2080 /* Create the folder */
2081 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2084 /* Call the user callback anyway */
2086 callback (self, parent, NULL, user_data);
2087 /* Notify about operation end */
2088 modest_mail_operation_notify_end (self);
2093 modest_mail_operation_remove_folder (ModestMailOperation *self,
2095 gboolean remove_to_trash)
2097 ModestMailOperationPrivate *priv;
2098 ModestTnyFolderRules rules;
2100 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2101 g_return_if_fail (TNY_IS_FOLDER (folder));
2103 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2105 /* Check folder rules */
2106 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2107 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2108 /* Set status failed and set an error */
2109 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2110 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2111 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2112 _("mail_in_ui_folder_delete_error"));
2116 /* Get the account */
2117 priv->account = modest_tny_folder_get_account (folder);
2118 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2120 /* Delete folder or move to trash */
2121 if (remove_to_trash) {
2122 TnyFolder *trash_folder = NULL;
2123 trash_folder = modest_tny_account_get_special_folder (priv->account,
2124 TNY_FOLDER_TYPE_TRASH);
2125 /* TODO: error_handling */
2127 modest_mail_operation_notify_start (self);
2128 modest_mail_operation_xfer_folder (self, folder,
2129 TNY_FOLDER_STORE (trash_folder),
2131 g_object_unref (trash_folder);
2133 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2136 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2138 modest_mail_operation_notify_start (self);
2139 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2140 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2143 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2145 g_object_unref (parent);
2147 g_warning ("%s: could not get parent folder", __FUNCTION__);
2151 /* Notify about operation end */
2152 modest_mail_operation_notify_end (self);
2156 transfer_folder_status_cb (GObject *obj,
2160 ModestMailOperation *self;
2161 ModestMailOperationPrivate *priv;
2162 ModestMailOperationState *state;
2163 XFerFolderAsyncHelper *helper;
2165 g_return_if_fail (status != NULL);
2167 /* Show only the status information we want */
2168 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2171 helper = (XFerFolderAsyncHelper *) user_data;
2172 g_return_if_fail (helper != NULL);
2174 self = helper->mail_op;
2175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2177 priv->done = status->position;
2178 priv->total = status->of_total;
2180 state = modest_mail_operation_clone_state (self);
2182 /* This is not a GDK lock because we are a Tinymail callback
2183 * which is already GDK locked by Tinymail */
2185 /* no gdk_threads_enter (), CHECKED */
2187 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2189 /* no gdk_threads_leave (), CHECKED */
2191 g_slice_free (ModestMailOperationState, state);
2195 transfer_folder_cb (TnyFolder *folder,
2197 TnyFolderStore *into,
2198 TnyFolder *new_folder,
2202 XFerFolderAsyncHelper *helper;
2203 ModestMailOperation *self = NULL;
2204 ModestMailOperationPrivate *priv = NULL;
2206 helper = (XFerFolderAsyncHelper *) user_data;
2207 g_return_if_fail (helper != NULL);
2209 self = helper->mail_op;
2210 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2213 priv->error = g_error_copy (err);
2215 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2216 } else if (cancelled) {
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2218 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2219 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2220 _("Transference of %s was cancelled."),
2221 tny_folder_get_name (folder));
2224 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2227 /* Update state of new folder */
2229 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2230 tny_folder_poke_status (new_folder);
2233 /* Notify about operation end */
2234 modest_mail_operation_notify_end (self);
2236 /* If user defined callback function was defined, call it */
2237 if (helper->user_callback) {
2239 /* This is not a GDK lock because we are a Tinymail callback
2240 * which is already GDK locked by Tinymail */
2242 /* no gdk_threads_enter (), CHECKED */
2243 helper->user_callback (self, new_folder, helper->user_data);
2244 /* no gdk_threads_leave () , CHECKED */
2248 g_object_unref (helper->mail_op);
2249 g_slice_free (XFerFolderAsyncHelper, helper);
2254 * This function checks if the new name is a valid name for our local
2255 * folders account. The new name could not be the same than then name
2256 * of any of the mandatory local folders
2258 * We can not rely on tinymail because tinymail does not check the
2259 * name of the virtual folders that the account could have in the case
2260 * that we're doing a rename (because it directly calls Camel which
2261 * knows nothing about our virtual folders).
2263 * In the case of an actual copy/move (i.e. move/copy a folder between
2264 * accounts) tinymail uses the tny_folder_store_create_account which
2265 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2266 * checks the new name of the folder, so this call in that case
2267 * wouldn't be needed. *But* NOTE that if tinymail changes its
2268 * implementation (if folder transfers within the same account is no
2269 * longer implemented as a rename) this call will allow Modest to work
2272 * If the new name is not valid, this function will set the status to
2273 * failed and will set also an error in the mail operation
2276 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2277 TnyFolderStore *into,
2278 const gchar *new_name)
2280 if (TNY_IS_ACCOUNT (into) &&
2281 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2282 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2284 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2285 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2286 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2287 _CS("ckdg_ib_folder_already_exists"));
2294 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2296 TnyFolderStore *parent,
2297 gboolean delete_original,
2298 XferFolderAsyncUserCallback user_callback,
2301 ModestMailOperationPrivate *priv = NULL;
2302 ModestTnyFolderRules parent_rules = 0, rules;
2303 XFerFolderAsyncHelper *helper = NULL;
2304 const gchar *folder_name = NULL;
2305 const gchar *error_msg;
2307 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2308 g_return_if_fail (TNY_IS_FOLDER (folder));
2309 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2312 folder_name = tny_folder_get_name (folder);
2314 /* Set the error msg */
2315 error_msg = _("mail_in_ui_folder_move_target_error");
2317 /* Get account and set it into mail_operation */
2318 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2319 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2320 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2322 /* Get folder rules */
2323 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2324 if (TNY_IS_FOLDER (parent))
2325 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2327 /* Apply operation constraints */
2328 if ((gpointer) parent == (gpointer) folder ||
2329 (!TNY_IS_FOLDER_STORE (parent)) ||
2330 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2333 } else if (TNY_IS_FOLDER (parent) &&
2334 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2338 } else if (TNY_IS_FOLDER (parent) &&
2339 TNY_IS_FOLDER_STORE (folder) &&
2340 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2341 TNY_FOLDER_STORE (folder))) {
2342 /* Do not move a parent into a child */
2344 } else if (TNY_IS_FOLDER_STORE (parent) &&
2345 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2346 /* Check that the new folder name is not used by any
2349 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2350 /* Check that the new folder name is not used by any
2351 special local folder */
2354 /* Create the helper */
2355 helper = g_slice_new0 (XFerFolderAsyncHelper);
2356 helper->mail_op = g_object_ref (self);
2357 helper->user_callback = user_callback;
2358 helper->user_data = user_data;
2360 /* Move/Copy folder */
2361 modest_mail_operation_notify_start (self);
2362 tny_folder_copy_async (folder,
2364 tny_folder_get_name (folder),
2367 transfer_folder_status_cb,
2373 /* Set status failed and set an error */
2374 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2375 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2376 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2379 /* Call the user callback if exists */
2381 user_callback (self, NULL, user_data);
2383 /* Notify the queue */
2384 modest_mail_operation_notify_end (self);
2388 modest_mail_operation_rename_folder (ModestMailOperation *self,
2391 XferFolderAsyncUserCallback user_callback,
2394 ModestMailOperationPrivate *priv;
2395 ModestTnyFolderRules rules;
2396 XFerFolderAsyncHelper *helper;
2398 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2399 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2400 g_return_if_fail (name);
2402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2404 /* Get account and set it into mail_operation */
2405 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2406 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2408 /* Check folder rules */
2409 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2410 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2412 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2415 TnyFolderStore *into;
2417 into = tny_folder_get_folder_store (folder);
2419 /* Check that the new folder name is not used by any
2420 special local folder */
2421 if (new_name_valid_if_local_account (priv, into, name)) {
2422 /* Create the helper */
2423 helper = g_slice_new0 (XFerFolderAsyncHelper);
2424 helper->mail_op = g_object_ref(self);
2425 helper->user_callback = user_callback;
2426 helper->user_data = user_data;
2428 /* Rename. Camel handles folder subscription/unsubscription */
2429 modest_mail_operation_notify_start (self);
2430 tny_folder_copy_async (folder, into, name, TRUE,
2432 transfer_folder_status_cb,
2434 g_object_unref (into);
2436 g_object_unref (into);
2443 /* Set status failed and set an error */
2444 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2445 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2446 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2447 _("FIXME: unable to rename"));
2450 user_callback (self, NULL, user_data);
2452 /* Notify about operation end */
2453 modest_mail_operation_notify_end (self);
2456 /* ******************************************************************* */
2457 /* ************************** MSG ACTIONS ************************* */
2458 /* ******************************************************************* */
2461 modest_mail_operation_get_msg (ModestMailOperation *self,
2463 gboolean progress_feedback,
2464 GetMsgAsyncUserCallback user_callback,
2467 GetMsgInfo *helper = NULL;
2469 ModestMailOperationPrivate *priv;
2471 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2472 g_return_if_fail (TNY_IS_HEADER (header));
2474 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2475 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2479 /* Check memory low */
2480 if (_check_memory_low (self)) {
2482 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2483 modest_mail_operation_notify_end (self);
2487 /* Get account and set it into mail_operation */
2488 folder = tny_header_get_folder (header);
2489 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2491 /* Check for cached messages */
2492 if (progress_feedback) {
2493 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2494 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2496 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2498 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2501 /* Create the helper */
2502 helper = g_slice_new0 (GetMsgInfo);
2503 helper->header = g_object_ref (header);
2504 helper->mail_op = g_object_ref (self);
2505 helper->user_callback = user_callback;
2506 helper->user_data = user_data;
2507 helper->destroy_notify = NULL;
2508 helper->last_total_bytes = 0;
2509 helper->sum_total_bytes = 0;
2510 helper->total_bytes = tny_header_get_message_size (header);
2511 helper->more_msgs = NULL;
2513 modest_mail_operation_notify_start (self);
2515 /* notify about the start of the operation */
2516 ModestMailOperationState *state;
2517 state = modest_mail_operation_clone_state (self);
2520 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2522 g_slice_free (ModestMailOperationState, state);
2524 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2526 g_object_unref (G_OBJECT (folder));
2530 get_msg_status_cb (GObject *obj,
2534 GetMsgInfo *helper = NULL;
2536 g_return_if_fail (status != NULL);
2538 /* Show only the status information we want */
2539 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2542 helper = (GetMsgInfo *) user_data;
2543 g_return_if_fail (helper != NULL);
2545 /* Notify progress */
2546 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2547 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2551 get_msg_async_cb (TnyFolder *folder,
2557 GetMsgInfo *info = NULL;
2558 ModestMailOperationPrivate *priv = NULL;
2561 info = (GetMsgInfo *) user_data;
2563 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2566 if (info->more_msgs) {
2567 tny_iterator_next (info->more_msgs);
2568 finished = (tny_iterator_is_done (info->more_msgs));
2570 finished = (priv->done == priv->total) ? TRUE : FALSE;
2573 /* If canceled by the user, ignore the error given by Tinymail */
2577 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2579 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2581 priv->error = g_error_copy ((const GError *) err);
2582 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2585 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2586 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2589 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2590 /* Set the success status before calling the user callback */
2591 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2595 /* Call the user callback */
2596 if (info->user_callback)
2597 info->user_callback (info->mail_op, info->header, canceled,
2598 msg, err, info->user_data);
2600 /* Notify about operation end if this is the last callback */
2602 /* Free user data */
2603 if (info->destroy_notify)
2604 info->destroy_notify (info->user_data);
2606 /* Notify about operation end */
2607 modest_mail_operation_notify_end (info->mail_op);
2610 if (info->more_msgs)
2611 g_object_unref (info->more_msgs);
2612 g_object_unref (info->header);
2613 g_object_unref (info->mail_op);
2614 g_slice_free (GetMsgInfo, info);
2615 } else if (info->more_msgs) {
2616 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2617 TnyFolder *folder = tny_header_get_folder (header);
2619 g_object_unref (info->header);
2620 info->header = g_object_ref (header);
2622 /* Retrieve the next message */
2623 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2625 g_object_unref (header);
2626 g_object_unref (folder);
2628 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2633 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2634 TnyList *header_list,
2635 GetMsgAsyncUserCallback user_callback,
2637 GDestroyNotify notify)
2639 ModestMailOperationPrivate *priv = NULL;
2641 TnyIterator *iter = NULL;
2642 gboolean has_uncached_messages;
2644 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2646 /* Init mail operation */
2647 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2648 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2650 priv->total = tny_list_get_length(header_list);
2652 /* Check memory low */
2653 if (_check_memory_low (self)) {
2654 if (user_callback) {
2655 TnyHeader *header = NULL;
2658 if (tny_list_get_length (header_list) > 0) {
2659 iter = tny_list_create_iterator (header_list);
2660 header = (TnyHeader *) tny_iterator_get_current (iter);
2661 g_object_unref (iter);
2663 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2665 g_object_unref (header);
2669 /* Notify about operation end */
2670 modest_mail_operation_notify_end (self);
2674 /* Check uncached messages */
2675 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2676 !has_uncached_messages && !tny_iterator_is_done (iter);
2677 tny_iterator_next (iter)) {
2680 header = (TnyHeader *) tny_iterator_get_current (iter);
2681 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2682 has_uncached_messages = TRUE;
2683 g_object_unref (header);
2685 g_object_unref (iter);
2686 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2688 /* Get account and set it into mail_operation */
2689 if (tny_list_get_length (header_list) >= 1) {
2690 TnyIterator *iterator = tny_list_create_iterator (header_list);
2691 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2693 TnyFolder *folder = tny_header_get_folder (header);
2695 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2696 g_object_unref (folder);
2698 g_object_unref (header);
2700 g_object_unref (iterator);
2703 msg_list_size = compute_message_list_size (header_list, 0);
2705 modest_mail_operation_notify_start (self);
2706 iter = tny_list_create_iterator (header_list);
2707 if (!tny_iterator_is_done (iter)) {
2708 /* notify about the start of the operation */
2709 ModestMailOperationState *state;
2710 state = modest_mail_operation_clone_state (self);
2713 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2716 GetMsgInfo *msg_info = NULL;
2717 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2718 TnyFolder *folder = tny_header_get_folder (header);
2720 /* Create the message info */
2721 msg_info = g_slice_new0 (GetMsgInfo);
2722 msg_info->mail_op = g_object_ref (self);
2723 msg_info->header = g_object_ref (header);
2724 msg_info->more_msgs = g_object_ref (iter);
2725 msg_info->user_callback = user_callback;
2726 msg_info->user_data = user_data;
2727 msg_info->destroy_notify = notify;
2728 msg_info->last_total_bytes = 0;
2729 msg_info->sum_total_bytes = 0;
2730 msg_info->total_bytes = msg_list_size;
2732 /* The callback will call it per each header */
2733 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2735 /* Free and go on */
2736 g_object_unref (header);
2737 g_object_unref (folder);
2738 g_slice_free (ModestMailOperationState, state);
2740 g_object_unref (iter);
2745 remove_msgs_async_cb (TnyFolder *folder,
2750 gboolean expunge, leave_on_server;
2751 const gchar *account_name;
2752 TnyAccount *account;
2753 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2754 ModestMailOperation *self;
2755 ModestMailOperationPrivate *priv;
2756 ModestProtocolRegistry *protocol_registry;
2758 self = (ModestMailOperation *) user_data;
2759 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2760 protocol_registry = modest_runtime_get_protocol_registry ();
2762 if (canceled || err) {
2763 /* If canceled by the user, ignore the error given by Tinymail */
2765 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2767 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2768 priv->error = g_error_copy ((const GError *) err);
2769 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2772 modest_mail_operation_notify_end (self);
2773 g_object_unref (self);
2777 account = tny_folder_get_account (folder);
2778 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2780 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2782 account_proto = modest_tny_account_get_protocol_type (account);
2783 g_object_unref (account);
2785 if ((modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) &&
2786 !leave_on_server) ||
2787 !modest_tny_folder_is_remote_folder (folder))
2793 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2798 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2800 gboolean remove_to_trash /*ignored*/)
2802 TnyFolder *folder = NULL;
2803 ModestMailOperationPrivate *priv;
2804 TnyIterator *iter = NULL;
2805 TnyHeader *header = NULL;
2806 TnyList *remove_headers = NULL;
2807 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2809 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2810 g_return_if_fail (TNY_IS_LIST (headers));
2812 if (remove_to_trash)
2813 g_warning ("remove to trash is not implemented");
2815 if (tny_list_get_length(headers) == 0) {
2816 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2817 goto cleanup; /* nothing to do */
2820 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2821 remove_headers = g_object_ref(headers);
2823 /* Get folder from first header and sync it */
2824 iter = tny_list_create_iterator (headers);
2825 header = TNY_HEADER (tny_iterator_get_current (iter));
2827 folder = tny_header_get_folder (header);
2828 if (!TNY_IS_FOLDER(folder)) {
2829 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2833 /* Don't remove messages that are being sent */
2834 if (modest_tny_folder_is_local_folder (folder)) {
2835 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2837 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2838 TnyTransportAccount *traccount = NULL;
2839 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2840 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2842 ModestTnySendQueueStatus status;
2843 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2845 if (TNY_IS_SEND_QUEUE (send_queue)) {
2846 TnyIterator *iter = tny_list_create_iterator(headers);
2847 g_object_unref(remove_headers);
2848 remove_headers = TNY_LIST(tny_simple_list_new());
2849 while (!tny_iterator_is_done(iter)) {
2851 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2852 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2853 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2854 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2855 tny_list_append(remove_headers, G_OBJECT(hdr));
2857 g_object_unref(hdr);
2859 tny_iterator_next(iter);
2861 g_object_unref(iter);
2863 g_object_unref(traccount);
2867 /* Get account and set it into mail_operation */
2868 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2869 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2870 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2872 /* remove message from folder */
2873 modest_mail_operation_notify_start (self);
2874 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2875 NULL, g_object_ref (self));
2879 g_object_unref (remove_headers);
2881 g_object_unref (header);
2883 g_object_unref (iter);
2885 g_object_unref (folder);
2889 notify_progress_of_multiple_messages (ModestMailOperation *self,
2891 gint *last_total_bytes,
2892 gint *sum_total_bytes,
2894 gboolean increment_done)
2896 ModestMailOperationPrivate *priv;
2897 ModestMailOperationState *state;
2898 gboolean is_num_bytes = FALSE;
2900 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2902 /* We know that tinymail sends us information about
2903 * transferred bytes with this particular message
2905 if (status->message)
2906 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2908 state = modest_mail_operation_clone_state (self);
2909 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2910 /* We know that we're in a different message when the
2911 total number of bytes to transfer is different. Of
2912 course it could fail if we're transferring messages
2913 of the same size, but this is a workarround */
2914 if (status->of_total != *last_total_bytes) {
2915 /* We need to increment the done when there is
2916 no information about each individual
2917 message, we need to do this in message
2918 transfers, and we don't do it for getting
2922 *sum_total_bytes += *last_total_bytes;
2923 *last_total_bytes = status->of_total;
2925 state->bytes_done += status->position + *sum_total_bytes;
2926 state->bytes_total = total_bytes;
2928 /* Notify the status change. Only notify about changes
2929 referred to bytes */
2930 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2934 g_slice_free (ModestMailOperationState, state);
2938 transfer_msgs_status_cb (GObject *obj,
2942 XFerMsgsAsyncHelper *helper;
2944 g_return_if_fail (status != NULL);
2946 /* Show only the status information we want */
2947 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2950 helper = (XFerMsgsAsyncHelper *) user_data;
2951 g_return_if_fail (helper != NULL);
2953 /* Notify progress */
2954 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2955 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2959 transfer_msgs_sync_folder_cb (TnyFolder *self,
2964 XFerMsgsAsyncHelper *helper;
2965 /* We don't care here about the results of the
2967 helper = (XFerMsgsAsyncHelper *) user_data;
2969 /* Notify about operation end */
2970 modest_mail_operation_notify_end (helper->mail_op);
2972 /* If user defined callback function was defined, call it */
2973 if (helper->user_callback)
2974 helper->user_callback (helper->mail_op, helper->user_data);
2977 if (helper->more_msgs)
2978 g_object_unref (helper->more_msgs);
2979 if (helper->headers)
2980 g_object_unref (helper->headers);
2981 if (helper->dest_folder)
2982 g_object_unref (helper->dest_folder);
2983 if (helper->mail_op)
2984 g_object_unref (helper->mail_op);
2985 g_slice_free (XFerMsgsAsyncHelper, helper);
2989 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2991 XFerMsgsAsyncHelper *helper;
2992 ModestMailOperation *self;
2993 ModestMailOperationPrivate *priv;
2994 gboolean finished = TRUE;
2996 helper = (XFerMsgsAsyncHelper *) user_data;
2997 self = helper->mail_op;
2999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3002 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3004 priv->error = g_error_copy (err);
3006 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3007 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3008 if (helper->more_msgs) {
3009 /* We'll transfer the next message in the list */
3010 tny_iterator_next (helper->more_msgs);
3011 if (!tny_iterator_is_done (helper->more_msgs)) {
3012 GObject *next_header;
3013 g_object_unref (helper->headers);
3014 helper->headers = tny_simple_list_new ();
3015 next_header = tny_iterator_get_current (helper->more_msgs);
3016 tny_list_append (helper->headers, next_header);
3017 g_object_unref (next_header);
3023 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3028 /* Synchronize the source folder contents. This should
3029 be done by tinymail but the camel_folder_sync it's
3030 actually disabled in transfer_msgs_thread_clean
3031 because it's supposed to cause hangs */
3032 tny_folder_sync_async (folder, helper->delete,
3033 transfer_msgs_sync_folder_cb,
3036 /* Transfer more messages */
3037 tny_folder_transfer_msgs_async (folder,
3039 helper->dest_folder,
3042 transfer_msgs_status_cb,
3047 /* Computes the size of the messages the headers in the list belongs
3048 to. If num_elements is different from 0 then it only takes into
3049 account the first num_elements for the calculation */
3051 compute_message_list_size (TnyList *headers,
3055 guint size = 0, element = 0;
3057 /* If num_elements is not valid then take all into account */
3058 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3059 num_elements = tny_list_get_length (headers);
3061 iter = tny_list_create_iterator (headers);
3062 while (!tny_iterator_is_done (iter) && element < num_elements) {
3063 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3064 size += tny_header_get_message_size (header);
3065 g_object_unref (header);
3066 tny_iterator_next (iter);
3069 g_object_unref (iter);
3075 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3078 gboolean delete_original,
3079 XferMsgsAsyncUserCallback user_callback,
3082 ModestMailOperationPrivate *priv = NULL;
3083 TnyIterator *iter = NULL;
3084 TnyFolder *src_folder = NULL;
3085 XFerMsgsAsyncHelper *helper = NULL;
3086 TnyHeader *header = NULL;
3087 ModestTnyFolderRules rules = 0;
3088 TnyAccount *dst_account = NULL;
3089 gboolean leave_on_server;
3090 ModestMailOperationState *state;
3091 ModestProtocolRegistry *protocol_registry;
3092 ModestProtocolType account_protocol;
3094 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3095 g_return_if_fail (headers && TNY_IS_LIST (headers));
3096 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3099 protocol_registry = modest_runtime_get_protocol_registry ();
3101 priv->total = tny_list_get_length (headers);
3103 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3104 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3106 /* Apply folder rules */
3107 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3108 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3109 /* Set status failed and set an error */
3110 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3111 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3112 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3113 _CS("ckct_ib_unable_to_paste_here"));
3114 /* Notify the queue */
3115 modest_mail_operation_notify_end (self);
3119 /* Get source folder */
3120 iter = tny_list_create_iterator (headers);
3121 header = TNY_HEADER (tny_iterator_get_current (iter));
3123 src_folder = tny_header_get_folder (header);
3124 g_object_unref (header);
3126 g_object_unref (iter);
3128 if (src_folder == NULL) {
3129 /* Notify the queue */
3130 modest_mail_operation_notify_end (self);
3132 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3137 /* Check folder source and destination */
3138 if (src_folder == folder) {
3139 /* Set status failed and set an error */
3140 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3141 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3142 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3143 _("mail_in_ui_folder_copy_target_error"));
3145 /* Notify the queue */
3146 modest_mail_operation_notify_end (self);
3149 g_object_unref (src_folder);
3153 /* Create the helper */
3154 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3155 helper->mail_op = g_object_ref(self);
3156 helper->dest_folder = g_object_ref(folder);
3157 helper->user_callback = user_callback;
3158 helper->user_data = user_data;
3159 helper->last_total_bytes = 0;
3160 helper->sum_total_bytes = 0;
3161 helper->total_bytes = compute_message_list_size (headers, 0);
3163 /* Get account and set it into mail_operation */
3164 priv->account = modest_tny_folder_get_account (src_folder);
3165 dst_account = modest_tny_folder_get_account (folder);
3167 if (priv->account == dst_account) {
3168 /* Transfer all messages at once using the fast
3169 * method. Note that depending on the server this
3170 * might not be that fast, and might not be
3171 * user-cancellable either */
3172 helper->headers = g_object_ref (headers);
3173 helper->more_msgs = NULL;
3175 /* Transfer messages one by one so the user can cancel
3178 helper->headers = tny_simple_list_new ();
3179 helper->more_msgs = tny_list_create_iterator (headers);
3180 hdr = tny_iterator_get_current (helper->more_msgs);
3181 tny_list_append (helper->headers, hdr);
3182 g_object_unref (hdr);
3185 /* If leave_on_server is set to TRUE then don't use
3186 delete_original, we always pass FALSE. This is because
3187 otherwise tinymail will try to sync the source folder and
3188 this could cause an error if we're offline while
3189 transferring an already downloaded message from a POP
3191 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3192 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3193 const gchar *account_name;
3195 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3196 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3199 leave_on_server = FALSE;
3202 /* Do not delete messages if leave on server is TRUE */
3203 helper->delete = (leave_on_server) ? FALSE : delete_original;
3205 modest_mail_operation_notify_start (self);
3207 /* Start notifying progress */
3208 state = modest_mail_operation_clone_state (self);
3211 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3212 g_slice_free (ModestMailOperationState, state);
3214 tny_folder_transfer_msgs_async (src_folder,
3219 transfer_msgs_status_cb,
3221 g_object_unref (src_folder);
3222 g_object_unref (dst_account);
3227 on_refresh_folder (TnyFolder *folder,
3232 RefreshAsyncHelper *helper = NULL;
3233 ModestMailOperation *self = NULL;
3234 ModestMailOperationPrivate *priv = NULL;
3236 helper = (RefreshAsyncHelper *) user_data;
3237 self = helper->mail_op;
3238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3240 g_return_if_fail(priv!=NULL);
3243 priv->error = g_error_copy (error);
3244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3249 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3250 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3251 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3252 _("Error trying to refresh the contents of %s"),
3253 tny_folder_get_name (folder));
3257 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3260 /* Call user defined callback, if it exists */
3261 if (helper->user_callback) {
3263 /* This is not a GDK lock because we are a Tinymail callback and
3264 * Tinymail already acquires the Gdk lock */
3265 helper->user_callback (self, folder, helper->user_data);
3269 g_slice_free (RefreshAsyncHelper, helper);
3271 /* Notify about operation end */
3272 modest_mail_operation_notify_end (self);
3273 g_object_unref(self);
3277 on_refresh_folder_status_update (GObject *obj,
3281 RefreshAsyncHelper *helper = NULL;
3282 ModestMailOperation *self = NULL;
3283 ModestMailOperationPrivate *priv = NULL;
3284 ModestMailOperationState *state;
3286 g_return_if_fail (user_data != NULL);
3287 g_return_if_fail (status != NULL);
3289 /* Show only the status information we want */
3290 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3293 helper = (RefreshAsyncHelper *) user_data;
3294 self = helper->mail_op;
3295 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3297 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3299 priv->done = status->position;
3300 priv->total = status->of_total;
3302 state = modest_mail_operation_clone_state (self);
3304 /* This is not a GDK lock because we are a Tinymail callback and
3305 * Tinymail already acquires the Gdk lock */
3306 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3308 g_slice_free (ModestMailOperationState, state);
3312 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3314 RefreshAsyncUserCallback user_callback,
3317 ModestMailOperationPrivate *priv = NULL;
3318 RefreshAsyncHelper *helper = NULL;
3320 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3322 /* Check memory low */
3323 if (_check_memory_low (self)) {
3325 user_callback (self, folder, user_data);
3326 /* Notify about operation end */
3327 modest_mail_operation_notify_end (self);
3331 /* Get account and set it into mail_operation */
3332 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3333 priv->account = modest_tny_folder_get_account (folder);
3334 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3336 /* Create the helper */
3337 helper = g_slice_new0 (RefreshAsyncHelper);
3338 helper->mail_op = g_object_ref(self);
3339 helper->user_callback = user_callback;
3340 helper->user_data = user_data;
3342 modest_mail_operation_notify_start (self);
3344 /* notify that the operation was started */
3345 ModestMailOperationState *state;
3346 state = modest_mail_operation_clone_state (self);
3349 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3351 g_slice_free (ModestMailOperationState, state);
3353 tny_folder_refresh_async (folder,
3355 on_refresh_folder_status_update,
3360 run_queue_notify_and_destroy (RunQueueHelper *helper,
3361 ModestMailOperationStatus status)
3363 ModestMailOperationPrivate *priv;
3366 if (helper->error_handler &&
3367 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3368 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3369 if (helper->start_handler &&
3370 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3371 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3372 if (helper->stop_handler &&
3373 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3374 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3378 priv->status = status;
3381 modest_mail_operation_notify_end (helper->self);
3384 g_object_unref (helper->queue);
3385 g_object_unref (helper->self);
3386 g_slice_free (RunQueueHelper, helper);
3390 run_queue_stop (ModestTnySendQueue *queue,
3393 RunQueueHelper *helper;
3395 g_debug ("%s sending queue stopped", __FUNCTION__);
3397 helper = (RunQueueHelper *) user_data;
3398 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3402 modest_mail_operation_run_queue (ModestMailOperation *self,
3403 ModestTnySendQueue *queue)
3405 ModestMailOperationPrivate *priv;
3406 RunQueueHelper *helper;
3408 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3409 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3412 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3413 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3414 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3416 /* Create the helper */
3417 helper = g_slice_new0 (RunQueueHelper);
3418 helper->queue = g_object_ref (queue);
3419 helper->self = g_object_ref (self);
3420 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3421 G_CALLBACK (run_queue_stop),
3424 /* Notify operation has started */
3425 modest_mail_operation_notify_start (self);
3426 g_debug ("%s, run queue started", __FUNCTION__);
3430 queue_wakeup_callback (ModestTnySendQueue *queue,
3435 ModestMailOperation *mail_op;
3436 ModestMailOperationPrivate *priv;
3438 mail_op = (ModestMailOperation *) userdata;
3439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3441 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3442 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3445 modest_mail_operation_notify_end (mail_op);
3446 g_object_unref (mail_op);
3450 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3451 ModestTnySendQueue *queue)
3453 ModestMailOperationPrivate *priv;
3455 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3456 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3459 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3460 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3461 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3463 g_object_ref (self);
3465 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3466 modest_mail_operation_notify_start (self);
3470 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3472 ModestMailOperation *self = (ModestMailOperation *) userdata;
3473 ModestMailOperationPrivate *priv;
3475 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3476 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3479 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3481 modest_mail_operation_notify_end (self);
3482 g_object_unref (self);
3486 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3488 ModestMailOperationPrivate *priv;
3490 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3491 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3494 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3496 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3497 priv->account = NULL;
3498 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3500 modest_mail_operation_notify_start (self);
3501 g_object_ref (self);
3502 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3506 sync_folder_finish_callback (TnyFolder *self,
3512 ModestMailOperation *mail_op;
3513 ModestMailOperationPrivate *priv;
3515 mail_op = (ModestMailOperation *) user_data;
3516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3518 /* If canceled by the user, ignore the error given by Tinymail */
3520 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3522 /* If the operation was a sync then the status is
3523 failed, but if it's part of another operation then
3524 just set it as finished with errors */
3525 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3526 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3528 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3529 priv->error = g_error_copy ((const GError *) err);
3530 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3532 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3535 modest_mail_operation_notify_end (mail_op);
3536 g_object_unref (mail_op);
3540 modest_mail_operation_sync_folder (ModestMailOperation *self,
3541 TnyFolder *folder, gboolean expunge)
3543 ModestMailOperationPrivate *priv;
3545 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3546 g_return_if_fail (TNY_IS_FOLDER (folder));
3547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3549 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3550 priv->account = modest_tny_folder_get_account (folder);
3551 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3553 modest_mail_operation_notify_start (self);
3554 g_object_ref (self);
3555 tny_folder_sync_async (folder, expunge,
3556 (TnyFolderCallback) sync_folder_finish_callback,
3561 modest_mail_operation_notify_start (ModestMailOperation *self)
3563 ModestMailOperationPrivate *priv = NULL;
3565 g_return_if_fail (self);
3567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3569 /* Ensure that all the fields are filled correctly */
3570 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3572 /* Notify the observers about the mail operation. We do not
3573 wrapp this emission because we assume that this function is
3574 always called from within the main lock */
3575 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3580 * It's used by the mail operation queue to notify the observers
3581 * attached to that signal that the operation finished. We need to use
3582 * that because tinymail does not give us the progress of a given
3583 * operation when it finishes (it directly calls the operation
3587 modest_mail_operation_notify_end (ModestMailOperation *self)
3589 ModestMailOperationPrivate *priv = NULL;
3591 g_return_if_fail (self);
3593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3595 /* Notify the observers about the mail operation end. We do
3596 not wrapp this emission because we assume that this
3597 function is always called from within the main lock */
3598 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3600 /* Remove the error user data */
3601 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3602 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3606 modest_mail_operation_get_account (ModestMailOperation *self)
3608 ModestMailOperationPrivate *priv = NULL;
3610 g_return_val_if_fail (self, NULL);
3612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3614 return (priv->account) ? g_object_ref (priv->account) : NULL;
3618 modest_mail_operation_noop (ModestMailOperation *self)
3620 ModestMailOperationPrivate *priv = NULL;
3622 g_return_if_fail (self);
3624 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3625 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3626 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3630 /* This mail operation does nothing actually */
3631 modest_mail_operation_notify_start (self);
3632 modest_mail_operation_notify_end (self);
3637 modest_mail_operation_to_string (ModestMailOperation *self)
3639 const gchar *type, *status, *account_id;
3640 ModestMailOperationPrivate *priv = NULL;
3642 g_return_val_if_fail (self, NULL);
3644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3646 /* new operations don't have anything interesting */
3647 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3648 return g_strdup_printf ("%p <new operation>", self);
3650 switch (priv->op_type) {
3651 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3652 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3653 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3654 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3655 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3656 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3657 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3658 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3659 default: type = "UNEXPECTED"; break;
3662 switch (priv->status) {
3663 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3664 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3665 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3666 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3667 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3668 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3669 default: status= "UNEXPECTED"; break;
3672 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3674 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3675 priv->done, priv->total,
3676 priv->error && priv->error->message ? priv->error->message : "");
3680 * Once the mail operations were objects this will be no longer
3681 * needed. I don't like it, but we need it for the moment
3684 _check_memory_low (ModestMailOperation *mail_op)
3686 if (modest_platform_check_memory_low (NULL, FALSE)) {
3687 ModestMailOperationPrivate *priv;
3689 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3690 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3691 g_set_error (&(priv->error),
3692 MODEST_MAIL_OPERATION_ERROR,
3693 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3694 "Not enough memory to complete the operation");