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-platform.h"
49 #include "modest-account-mgr-helpers.h"
50 #include <modest-tny-account.h>
51 #include <modest-tny-send-queue.h>
52 #include <modest-runtime.h>
53 #include "modest-text-utils.h"
54 #include "modest-tny-msg.h"
55 #include "modest-tny-folder.h"
56 #include "modest-tny-account-store.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-marshal.h"
59 #include "modest-error.h"
60 #include "modest-mail-operation.h"
61 #include <modest-count-stream.h>
62 #include <libgnomevfs/gnome-vfs.h>
63 #include "modest-utils.h"
64 #include "modest-debug.h"
69 * Remove all these #ifdef stuff when the tinymail's idle calls become
72 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
74 /* 'private'/'protected' functions */
75 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
76 static void modest_mail_operation_init (ModestMailOperation *obj);
77 static void modest_mail_operation_finalize (GObject *obj);
79 static void get_msg_async_cb (TnyFolder *folder,
85 static void get_msg_status_cb (GObject *obj,
89 static void modest_mail_operation_notify_start (ModestMailOperation *self);
90 static void modest_mail_operation_notify_end (ModestMailOperation *self);
92 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
94 gint *last_total_bytes,
95 gint *sum_total_bytes,
97 gboolean increment_done);
99 static guint compute_message_list_size (TnyList *headers, guint num_elements);
101 static int compare_headers_by_date (gconstpointer a,
104 static void sync_folder_finish_callback (TnyFolder *self,
109 static gboolean _check_memory_low (ModestMailOperation *mail_op);
113 ModestTnySendQueue *queue;
114 ModestMailOperation *self;
120 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
121 ModestMailOperationStatus status);
123 /* Helpers for the update account operation (send & receive)*/
126 ModestMailOperation *mail_op;
128 UpdateAccountCallback callback;
133 TnyFolderObserver *inbox_observer;
134 RetrieveAllCallback retrieve_all_cb;
135 gboolean interactive;
139 static void destroy_update_account_info (UpdateAccountInfo *info);
141 static void update_account_send_mail (UpdateAccountInfo *info);
143 static void update_account_get_msg_async_cb (TnyFolder *folder,
149 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
150 TnyList *new_headers);
152 enum _ModestMailOperationSignals
154 PROGRESS_CHANGED_SIGNAL,
155 OPERATION_STARTED_SIGNAL,
156 OPERATION_FINISHED_SIGNAL,
160 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
161 struct _ModestMailOperationPrivate {
167 ErrorCheckingUserCallback error_checking;
168 gpointer error_checking_user_data;
169 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
170 ModestMailOperationStatus status;
171 ModestMailOperationTypeOperation op_type;
174 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
175 MODEST_TYPE_MAIL_OPERATION, \
176 ModestMailOperationPrivate))
178 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
179 priv->status = new_status;\
184 GetMsgAsyncUserCallback user_callback;
186 TnyIterator *more_msgs;
188 ModestMailOperation *mail_op;
189 GDestroyNotify destroy_notify;
190 gint last_total_bytes;
191 gint sum_total_bytes;
195 typedef struct _RefreshAsyncHelper {
196 ModestMailOperation *mail_op;
197 RefreshAsyncUserCallback user_callback;
199 } RefreshAsyncHelper;
201 typedef struct _XFerMsgsAsyncHelper
203 ModestMailOperation *mail_op;
205 TnyIterator *more_msgs;
206 TnyFolder *dest_folder;
207 XferMsgsAsyncUserCallback user_callback;
210 gint last_total_bytes;
211 gint sum_total_bytes;
213 } XFerMsgsAsyncHelper;
215 typedef struct _XFerFolderAsyncHelper
217 ModestMailOperation *mail_op;
218 XferFolderAsyncUserCallback user_callback;
220 } XFerFolderAsyncHelper;
222 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
226 static void modest_mail_operation_create_msg (ModestMailOperation *self,
227 const gchar *from, const gchar *to,
228 const gchar *cc, const gchar *bcc,
229 const gchar *subject, const gchar *plain_body,
230 const gchar *html_body, const GList *attachments_list,
231 const GList *images_list,
232 TnyHeaderFlags priority_flags,
233 ModestMailOperationCreateMsgCallback callback,
236 static gboolean idle_notify_queue (gpointer data);
239 ModestMailOperation *mail_op;
247 GList *attachments_list;
249 TnyHeaderFlags priority_flags;
250 ModestMailOperationCreateMsgCallback callback;
256 ModestMailOperation *mail_op;
258 ModestMailOperationCreateMsgCallback callback;
263 static GObjectClass *parent_class = NULL;
265 static guint signals[NUM_SIGNALS] = {0};
268 modest_mail_operation_get_type (void)
270 static GType my_type = 0;
272 static const GTypeInfo my_info = {
273 sizeof(ModestMailOperationClass),
274 NULL, /* base init */
275 NULL, /* base finalize */
276 (GClassInitFunc) modest_mail_operation_class_init,
277 NULL, /* class finalize */
278 NULL, /* class data */
279 sizeof(ModestMailOperation),
281 (GInstanceInitFunc) modest_mail_operation_init,
284 my_type = g_type_register_static (G_TYPE_OBJECT,
285 "ModestMailOperation",
292 modest_mail_operation_class_init (ModestMailOperationClass *klass)
294 GObjectClass *gobject_class;
295 gobject_class = (GObjectClass*) klass;
297 parent_class = g_type_class_peek_parent (klass);
298 gobject_class->finalize = modest_mail_operation_finalize;
300 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
303 * ModestMailOperation::progress-changed
304 * @self: the #MailOperation that emits the signal
305 * @user_data: user data set when the signal handler was connected
307 * Emitted when the progress of a mail operation changes
309 signals[PROGRESS_CHANGED_SIGNAL] =
310 g_signal_new ("progress-changed",
311 G_TYPE_FROM_CLASS (gobject_class),
313 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
315 g_cclosure_marshal_VOID__POINTER,
316 G_TYPE_NONE, 1, G_TYPE_POINTER);
320 * This signal is issued whenever a mail operation starts, and
321 * starts mean when the tinymail operation is issued. This
322 * means that it could happen that something wrong happens and
323 * the tinymail function is never called. In this situation a
324 * operation-finished will be issued without any
327 signals[OPERATION_STARTED_SIGNAL] =
328 g_signal_new ("operation-started",
329 G_TYPE_FROM_CLASS (gobject_class),
331 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
333 g_cclosure_marshal_VOID__VOID,
338 * This signal is issued whenever a mail operation
339 * finishes. Note that this signal could be issued without any
340 * previous "operation-started" signal, because this last one
341 * is only issued when the tinymail operation is successfully
344 signals[OPERATION_FINISHED_SIGNAL] =
345 g_signal_new ("operation-finished",
346 G_TYPE_FROM_CLASS (gobject_class),
348 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
350 g_cclosure_marshal_VOID__VOID,
355 modest_mail_operation_init (ModestMailOperation *obj)
357 ModestMailOperationPrivate *priv;
359 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
361 priv->account = NULL;
362 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
363 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
368 priv->error_checking = NULL;
369 priv->error_checking_user_data = NULL;
373 modest_mail_operation_finalize (GObject *obj)
375 ModestMailOperationPrivate *priv;
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
382 g_error_free (priv->error);
386 g_object_unref (priv->source);
390 g_object_unref (priv->account);
391 priv->account = NULL;
395 G_OBJECT_CLASS(parent_class)->finalize (obj);
399 modest_mail_operation_new (GObject *source)
401 ModestMailOperation *obj;
402 ModestMailOperationPrivate *priv;
404 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
408 priv->source = g_object_ref(source);
414 modest_mail_operation_new_with_error_handling (GObject *source,
415 ErrorCheckingUserCallback error_handler,
417 ErrorCheckingUserDataDestroyer error_handler_destroyer)
419 ModestMailOperation *obj;
420 ModestMailOperationPrivate *priv;
422 obj = modest_mail_operation_new (source);
423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
425 g_return_val_if_fail (error_handler != NULL, obj);
426 priv->error_checking = error_handler;
427 priv->error_checking_user_data = user_data;
428 priv->error_checking_user_data_destroyer = error_handler_destroyer;
434 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
436 ModestMailOperationPrivate *priv;
438 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
440 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
441 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
443 /* Call the user callback */
444 if (priv->error_checking != NULL)
445 priv->error_checking (self, priv->error_checking_user_data);
449 ModestMailOperationTypeOperation
450 modest_mail_operation_get_type_operation (ModestMailOperation *self)
452 ModestMailOperationPrivate *priv;
454 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
455 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 return priv->op_type;
463 modest_mail_operation_is_mine (ModestMailOperation *self,
466 ModestMailOperationPrivate *priv;
468 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
471 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
472 if (priv->source == NULL) return FALSE;
474 return priv->source == me;
478 modest_mail_operation_get_source (ModestMailOperation *self)
480 ModestMailOperationPrivate *priv;
482 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
485 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
487 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
491 return (priv->source) ? g_object_ref (priv->source) : NULL;
494 ModestMailOperationStatus
495 modest_mail_operation_get_status (ModestMailOperation *self)
497 ModestMailOperationPrivate *priv;
499 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
500 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
501 MODEST_MAIL_OPERATION_STATUS_INVALID);
503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
505 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
506 return MODEST_MAIL_OPERATION_STATUS_INVALID;
513 modest_mail_operation_get_error (ModestMailOperation *self)
515 ModestMailOperationPrivate *priv;
517 g_return_val_if_fail (self, NULL);
518 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
531 modest_mail_operation_cancel (ModestMailOperation *self)
533 ModestMailOperationPrivate *priv;
534 gboolean canceled = FALSE;
536 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
538 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
541 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
543 /* Cancel the mail operation */
544 g_return_val_if_fail (priv->account, FALSE);
545 tny_account_cancel (priv->account);
547 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
548 ModestTnySendQueue *queue;
549 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
552 /* Cancel the sending of the following next messages */
553 if (TNY_IS_SEND_QUEUE (queue))
554 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
561 modest_mail_operation_get_task_done (ModestMailOperation *self)
563 ModestMailOperationPrivate *priv;
565 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
568 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
573 modest_mail_operation_get_task_total (ModestMailOperation *self)
575 ModestMailOperationPrivate *priv;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
585 modest_mail_operation_is_finished (ModestMailOperation *self)
587 ModestMailOperationPrivate *priv;
588 gboolean retval = FALSE;
590 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
595 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
596 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
597 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
598 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
608 * Creates an image of the current state of a mail operation, the
609 * caller must free it
611 static ModestMailOperationState *
612 modest_mail_operation_clone_state (ModestMailOperation *self)
614 ModestMailOperationState *state;
615 ModestMailOperationPrivate *priv;
617 /* FIXME: this should be fixed properly
619 * in some cases, priv was NULL, so checking here to
622 g_return_val_if_fail (self, NULL);
623 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
624 g_return_val_if_fail (priv, NULL);
629 state = g_slice_new (ModestMailOperationState);
631 state->status = priv->status;
632 state->op_type = priv->op_type;
633 state->done = priv->done;
634 state->total = priv->total;
635 state->finished = modest_mail_operation_is_finished (self);
636 state->bytes_done = 0;
637 state->bytes_total = 0;
642 /* ******************************************************************* */
643 /* ************************** SEND ACTIONS ************************* */
644 /* ******************************************************************* */
648 ModestMailOperation *mail_op;
653 send_mail_on_sync_async_cb (TnyFolder *folder,
658 ModestMailOperationPrivate *priv;
659 ModestMailOperation *self;
660 SendNewMailHelper *helper;
662 helper = (SendNewMailHelper *) user_data;
663 self = helper->mail_op;
664 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
666 if (cancelled || err)
670 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
671 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
672 "Error adding a msg to the send queue\n");
673 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
675 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
680 modest_mail_operation_notify_end (self);
682 g_object_unref (helper->mail_op);
683 g_slice_free (SendNewMailHelper, helper);
687 run_queue_start (TnySendQueue *self,
690 RunQueueHelper *helper = (RunQueueHelper *) user_data;
691 ModestMailOperation *mail_op;
693 g_debug ("%s sending queue successfully started", __FUNCTION__);
695 /* Wait for the message to be sent */
696 mail_op = modest_mail_operation_new (NULL);
697 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
699 modest_mail_operation_run_queue (mail_op, helper->queue);
700 g_object_unref (mail_op);
702 /* Free the helper and end operation */
703 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
707 run_queue_error_happened (TnySendQueue *queue,
713 RunQueueHelper *helper = (RunQueueHelper *) user_data;
714 ModestMailOperationPrivate *priv;
716 /* If we are here this means that the send queue could not
717 start to send emails. Shouldn't happen as this means that
718 we could not create the thread */
719 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
721 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
722 priv->error = g_error_copy ((const GError *) error);
724 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
725 /* This code is here for safety reasons. It should
726 never be called, because that would mean that we
727 are not controlling some error case */
728 g_warning ("%s Error %s should not happen",
729 __FUNCTION__, error->message);
732 /* Free helper and end operation */
733 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
737 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
743 ModestMailOperationPrivate *priv;
744 ModestMailOperation *self;
745 SendNewMailHelper *helper;
747 helper = (SendNewMailHelper *) user_data;
748 self = helper->mail_op;
749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
751 if (cancelled || err)
755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
756 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
757 "Error adding a msg to the send queue\n");
758 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
760 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
764 if (helper->notify) {
765 TnyTransportAccount *trans_account;
766 ModestTnySendQueue *queue;
768 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
769 queue = modest_runtime_get_send_queue (trans_account, TRUE);
771 RunQueueHelper *helper;
773 /* Create the helper */
774 helper = g_slice_new0 (RunQueueHelper);
775 helper->queue = g_object_ref (queue);
776 helper->self = g_object_ref (self);
778 /* if sending is ongoing wait for the queue to
779 stop. Otherwise wait for the queue-start
780 signal. It could happen that the queue
781 could not start, then check also the error
783 if (modest_tny_send_queue_sending_in_progress (queue)) {
784 run_queue_start (TNY_SEND_QUEUE (queue), helper);
786 helper->start_handler = g_signal_connect (queue, "queue-start",
787 G_CALLBACK (run_queue_start),
789 helper->error_handler = g_signal_connect (queue, "error-happened",
790 G_CALLBACK (run_queue_error_happened),
794 /* Finalize this mail operation */
795 modest_mail_operation_notify_end (self);
797 g_object_unref (trans_account);
800 g_object_unref (helper->mail_op);
801 g_slice_free (SendNewMailHelper, helper);
805 idle_create_msg_cb (gpointer idle_data)
807 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
809 /* This is a GDK lock because we are an idle callback and
810 * info->callback can contain Gtk+ code */
812 gdk_threads_enter (); /* CHECKED */
813 info->callback (info->mail_op, info->msg, info->userdata);
815 g_object_unref (info->mail_op);
817 g_object_unref (info->msg);
818 g_slice_free (CreateMsgIdleInfo, info);
819 gdk_threads_leave (); /* CHECKED */
825 create_msg_thread (gpointer thread_data)
827 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
828 TnyMsg *new_msg = NULL;
829 ModestMailOperationPrivate *priv;
831 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
832 if (info->html_body == NULL) {
833 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
834 info->bcc, info->subject, info->plain_body,
835 info->attachments_list,
838 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
839 info->bcc, info->subject, info->html_body,
840 info->plain_body, info->attachments_list,
848 /* Set priority flags in message */
849 header = tny_msg_get_header (new_msg);
850 tny_header_set_flag (header, info->priority_flags);
852 /* Set attachment flags in message */
853 if (info->attachments_list != NULL)
854 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
856 g_object_unref (G_OBJECT(header));
858 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
860 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
861 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
862 "modest: failed to create a new msg\n");
870 g_free (info->plain_body);
871 g_free (info->html_body);
872 g_free (info->subject);
873 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
874 g_list_free (info->attachments_list);
875 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
876 g_list_free (info->images_list);
878 if (info->callback) {
879 CreateMsgIdleInfo *idle_info;
880 idle_info = g_slice_new0 (CreateMsgIdleInfo);
881 idle_info->mail_op = g_object_ref (info->mail_op);
882 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
883 idle_info->callback = info->callback;
884 idle_info->userdata = info->userdata;
885 g_idle_add (idle_create_msg_cb, idle_info);
887 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
890 g_object_unref (info->mail_op);
891 g_slice_free (CreateMsgInfo, info);
892 if (new_msg) g_object_unref(new_msg);
898 modest_mail_operation_create_msg (ModestMailOperation *self,
899 const gchar *from, const gchar *to,
900 const gchar *cc, const gchar *bcc,
901 const gchar *subject, const gchar *plain_body,
902 const gchar *html_body,
903 const GList *attachments_list,
904 const GList *images_list,
905 TnyHeaderFlags priority_flags,
906 ModestMailOperationCreateMsgCallback callback,
909 CreateMsgInfo *info = NULL;
911 info = g_slice_new0 (CreateMsgInfo);
912 info->mail_op = g_object_ref (self);
914 info->from = g_strdup (from);
915 info->to = g_strdup (to);
916 info->cc = g_strdup (cc);
917 info->bcc = g_strdup (bcc);
918 info->subject = g_strdup (subject);
919 info->plain_body = g_strdup (plain_body);
920 info->html_body = g_strdup (html_body);
921 info->attachments_list = g_list_copy ((GList *) attachments_list);
922 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
923 info->images_list = g_list_copy ((GList *) images_list);
924 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
925 info->priority_flags = priority_flags;
927 info->callback = callback;
928 info->userdata = userdata;
930 g_thread_create (create_msg_thread, info, FALSE, NULL);
935 TnyTransportAccount *transport_account;
940 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
944 TnySendQueue *send_queue = NULL;
945 ModestMailOperationPrivate *priv = NULL;
946 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
947 TnyFolder *draft_folder = NULL;
948 TnyFolder *outbox_folder = NULL;
949 TnyHeader *header = NULL;
951 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
954 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
955 modest_mail_operation_notify_end (self);
959 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
960 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
961 modest_mail_operation_notify_end (self);
965 /* Add message to send queue */
966 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
967 if (!TNY_IS_SEND_QUEUE(send_queue)) {
969 g_error_free (priv->error);
972 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
973 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
974 "modest: could not find send queue for account\n");
975 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
976 modest_mail_operation_notify_end (self);
979 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
980 helper->mail_op = g_object_ref (self);
981 helper->notify = (info->draft_msg == NULL);
983 /* Add the msg to the queue. The callback will free
985 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
987 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
991 if (info->draft_msg != NULL) {
992 TnyList *tmp_headers = NULL;
993 TnyFolder *folder = NULL;
994 TnyFolder *src_folder = NULL;
995 TnyFolderType folder_type;
996 TnyTransportAccount *transport_account = NULL;
997 SendNewMailHelper *helper = NULL;
999 /* To remove the old mail from its source folder, we need to get the
1000 * transport account of the original draft message (the transport account
1001 * might have been changed by the user) */
1002 header = tny_msg_get_header (info->draft_msg);
1003 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1004 modest_runtime_get_account_store(), header);
1005 if (transport_account == NULL)
1006 transport_account = g_object_ref(info->transport_account);
1007 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1008 TNY_FOLDER_TYPE_DRAFTS);
1009 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1010 TNY_FOLDER_TYPE_OUTBOX);
1011 g_object_unref(transport_account);
1013 if (!draft_folder) {
1014 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1016 modest_mail_operation_notify_end (self);
1019 if (!outbox_folder) {
1020 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1022 modest_mail_operation_notify_end (self);
1026 folder = tny_msg_get_folder (info->draft_msg);
1027 if (folder == NULL) {
1028 modest_mail_operation_notify_end (self);
1031 folder_type = modest_tny_folder_guess_folder_type (folder);
1033 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1034 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1036 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1037 src_folder = outbox_folder;
1039 src_folder = draft_folder;
1041 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1042 * because this function requires it to have a UID. */
1043 helper = g_slice_new (SendNewMailHelper);
1044 helper->mail_op = g_object_ref (self);
1045 helper->notify = TRUE;
1047 tmp_headers = tny_simple_list_new ();
1048 tny_list_append (tmp_headers, (GObject*) header);
1049 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1050 g_object_unref (tmp_headers);
1051 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1053 g_object_unref (folder);
1058 g_object_unref (header);
1059 if (info->draft_msg)
1060 g_object_unref (info->draft_msg);
1062 g_object_unref (draft_folder);
1064 g_object_unref (outbox_folder);
1065 if (info->transport_account)
1066 g_object_unref (info->transport_account);
1067 g_slice_free (SendNewMailInfo, info);
1071 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1072 TnyTransportAccount *transport_account,
1074 const gchar *from, const gchar *to,
1075 const gchar *cc, const gchar *bcc,
1076 const gchar *subject, const gchar *plain_body,
1077 const gchar *html_body,
1078 const GList *attachments_list,
1079 const GList *images_list,
1080 TnyHeaderFlags priority_flags)
1082 ModestMailOperationPrivate *priv = NULL;
1083 SendNewMailInfo *info;
1085 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1086 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1088 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1089 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1090 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1091 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1093 modest_mail_operation_notify_start (self);
1095 /* Check parametters */
1097 /* Set status failed and set an error */
1098 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1099 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1100 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1101 _("Error trying to send a mail. You need to set at least one recipient"));
1102 modest_mail_operation_notify_end (self);
1105 info = g_slice_new0 (SendNewMailInfo);
1106 info->transport_account = transport_account;
1107 if (transport_account)
1108 g_object_ref (transport_account);
1109 info->draft_msg = draft_msg;
1111 g_object_ref (draft_msg);
1114 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1115 attachments_list, images_list, priority_flags,
1116 modest_mail_operation_send_new_mail_cb, info);
1122 TnyTransportAccount *transport_account;
1124 SaveToDraftstCallback callback;
1128 ModestMailOperation *mailop;
1129 } SaveToDraftsAddMsgInfo;
1132 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1137 ModestMailOperationPrivate *priv = NULL;
1138 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1139 GError *io_error = NULL;
1141 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1143 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1144 io_error = priv->error;
1148 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1149 g_error_free(priv->error);
1152 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1154 if ((!priv->error) && (info->draft_msg != NULL)) {
1155 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1156 TnyFolder *src_folder = tny_header_get_folder (header);
1158 g_debug ("--- REMOVE AND SYNC");
1159 /* Remove the old draft */
1160 tny_folder_remove_msg (src_folder, header, NULL);
1162 /* Synchronize to expunge and to update the msg counts */
1163 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1164 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1165 g_debug ("--- REMOVED - SYNCED");
1167 g_object_unref (G_OBJECT(header));
1168 g_object_unref (G_OBJECT(src_folder));
1172 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1174 g_error_free (io_error);
1177 } else if (io_error) {
1178 priv->error = io_error;
1179 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1181 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1184 /* Call the user callback */
1186 info->callback (info->mailop, info->msg, info->user_data);
1188 if (info->transport_account)
1189 g_object_unref (G_OBJECT(info->transport_account));
1190 if (info->draft_msg)
1191 g_object_unref (G_OBJECT (info->draft_msg));
1193 g_object_unref (G_OBJECT(info->drafts));
1195 g_object_unref (G_OBJECT (info->msg));
1197 modest_mail_operation_notify_end (info->mailop);
1198 g_object_unref(info->mailop);
1199 g_slice_free (SaveToDraftsAddMsgInfo, info);
1204 TnyTransportAccount *transport_account;
1206 SaveToDraftstCallback callback;
1211 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1215 TnyFolder *drafts = NULL;
1216 ModestMailOperationPrivate *priv = NULL;
1217 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1219 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1222 if (!(priv->error)) {
1223 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1224 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1225 "modest: failed to create a new msg\n");
1228 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1229 TNY_FOLDER_TYPE_DRAFTS);
1230 if (!drafts && !(priv->error)) {
1231 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1232 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1233 "modest: failed to create a new msg\n");
1237 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1238 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1239 cb_info->transport_account = g_object_ref(info->transport_account);
1240 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1241 cb_info->callback = info->callback;
1242 cb_info->user_data = info->user_data;
1243 cb_info->drafts = g_object_ref(drafts);
1244 cb_info->msg = g_object_ref(msg);
1245 cb_info->mailop = g_object_ref(self);
1246 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1249 /* Call the user callback */
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1252 info->callback (self, msg, info->user_data);
1253 modest_mail_operation_notify_end (self);
1257 g_object_unref (G_OBJECT(drafts));
1258 if (info->draft_msg)
1259 g_object_unref (G_OBJECT (info->draft_msg));
1260 if (info->transport_account)
1261 g_object_unref (G_OBJECT(info->transport_account));
1262 g_slice_free (SaveToDraftsInfo, info);
1266 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1267 TnyTransportAccount *transport_account,
1269 const gchar *from, const gchar *to,
1270 const gchar *cc, const gchar *bcc,
1271 const gchar *subject, const gchar *plain_body,
1272 const gchar *html_body,
1273 const GList *attachments_list,
1274 const GList *images_list,
1275 TnyHeaderFlags priority_flags,
1276 SaveToDraftstCallback callback,
1279 ModestMailOperationPrivate *priv = NULL;
1280 SaveToDraftsInfo *info = NULL;
1282 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1283 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1287 /* Get account and set it into mail_operation */
1288 priv->account = g_object_ref (transport_account);
1289 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1291 info = g_slice_new0 (SaveToDraftsInfo);
1292 info->transport_account = g_object_ref (transport_account);
1293 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1294 info->callback = callback;
1295 info->user_data = user_data;
1297 g_debug ("--- CREATE MESSAGE");
1298 modest_mail_operation_notify_start (self);
1299 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1300 attachments_list, images_list, priority_flags,
1301 modest_mail_operation_save_to_drafts_cb, info);
1306 ModestMailOperation *mail_op;
1307 TnyMimePart *mime_part;
1309 GetMimePartSizeCallback callback;
1311 } GetMimePartSizeInfo;
1313 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1314 /* We use this folder observer to track the headers that have been
1315 * added to a folder */
1318 TnyList *new_headers;
1319 } InternalFolderObserver;
1322 GObjectClass parent;
1323 } InternalFolderObserverClass;
1325 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1327 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1328 internal_folder_observer,
1330 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1334 foreach_add_item (gpointer header, gpointer user_data)
1336 tny_list_prepend (TNY_LIST (user_data),
1340 /* This is the method that looks for new messages in a folder */
1342 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1344 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1346 TnyFolderChangeChanged changed;
1348 changed = tny_folder_change_get_changed (change);
1350 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1353 /* Get added headers */
1354 list = tny_simple_list_new ();
1355 tny_folder_change_get_added_headers (change, list);
1357 /* Add them to the folder observer */
1358 tny_list_foreach (list, foreach_add_item,
1359 derived->new_headers);
1361 g_object_unref (G_OBJECT (list));
1366 internal_folder_observer_init (InternalFolderObserver *self)
1368 self->new_headers = tny_simple_list_new ();
1371 internal_folder_observer_finalize (GObject *object)
1373 InternalFolderObserver *self;
1375 self = (InternalFolderObserver *) object;
1376 g_object_unref (self->new_headers);
1378 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1381 tny_folder_observer_init (TnyFolderObserverIface *iface)
1383 iface->update = internal_folder_observer_update;
1386 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1388 GObjectClass *object_class;
1390 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1391 object_class = (GObjectClass*) klass;
1392 object_class->finalize = internal_folder_observer_finalize;
1396 destroy_update_account_info (UpdateAccountInfo *info)
1398 g_free (info->account_name);
1399 g_object_unref (info->folders);
1400 g_object_unref (info->mail_op);
1401 g_slice_free (UpdateAccountInfo, info);
1406 update_account_send_mail (UpdateAccountInfo *info)
1408 TnyTransportAccount *transport_account = NULL;
1409 ModestTnyAccountStore *account_store;
1411 account_store = modest_runtime_get_account_store ();
1413 /* We don't try to send messages while sending mails is blocked */
1414 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1417 /* Get the transport account */
1418 transport_account = (TnyTransportAccount *)
1419 modest_tny_account_store_get_transport_account_for_open_connection (account_store,
1420 info->account_name);
1422 if (transport_account) {
1423 ModestTnySendQueue *send_queue;
1427 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1428 g_object_unref (transport_account);
1430 if (TNY_IS_SEND_QUEUE (send_queue)) {
1431 /* Get outbox folder */
1432 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1433 if (outbox) { /* this could fail in some cases */
1434 num_messages = tny_folder_get_all_count (outbox);
1435 g_object_unref (outbox);
1437 g_warning ("%s: could not get outbox", __FUNCTION__);
1441 if (num_messages != 0) {
1442 /* Reenable suspended items */
1443 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1446 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1447 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1455 update_account_get_msg_async_cb (TnyFolder *folder,
1461 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1462 ModestMailOperationPrivate *priv;
1464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1467 if (TNY_IS_MSG (msg)) {
1468 TnyHeader *header = tny_msg_get_header (msg);
1471 ModestMailOperationState *state;
1472 state = modest_mail_operation_clone_state (msg_info->mail_op);
1473 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1474 state->bytes_done = msg_info->sum_total_bytes;
1475 state->bytes_total = msg_info->total_bytes;
1477 /* Notify the status change. Only notify about changes
1478 referred to bytes */
1479 g_signal_emit (G_OBJECT (msg_info->mail_op),
1480 signals[PROGRESS_CHANGED_SIGNAL],
1483 g_object_unref (header);
1484 g_slice_free (ModestMailOperationState, state);
1488 if (priv->done == priv->total) {
1489 TnyList *new_headers;
1490 UpdateAccountInfo *info;
1492 /* After getting all the messages send the ones in the
1494 info = (UpdateAccountInfo *) msg_info->user_data;
1495 update_account_send_mail (info);
1497 /* Check if the operation was a success */
1499 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1501 /* Call the user callback and free */
1502 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1503 update_account_notify_user_and_free (info, new_headers);
1504 g_object_unref (new_headers);
1506 /* Delete the helper */
1507 g_object_unref (msg_info->more_msgs);
1508 g_object_unref (msg_info->mail_op);
1509 g_slice_free (GetMsgInfo, msg_info);
1514 update_account_notify_user_and_free (UpdateAccountInfo *info,
1515 TnyList *new_headers)
1517 /* Set the account back to not busy */
1518 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1519 info->account_name, FALSE);
1523 info->callback (info->mail_op, new_headers, info->user_data);
1525 /* Mail operation end */
1526 modest_mail_operation_notify_end (info->mail_op);
1530 g_object_unref (new_headers);
1531 destroy_update_account_info (info);
1535 inbox_refreshed_cb (TnyFolder *inbox,
1540 UpdateAccountInfo *info;
1541 ModestMailOperationPrivate *priv;
1542 TnyIterator *new_headers_iter;
1543 GPtrArray *new_headers_array = NULL;
1544 gint max_size, retrieve_limit, i;
1545 ModestAccountMgr *mgr;
1546 ModestAccountRetrieveType retrieve_type;
1547 TnyList *new_headers = NULL;
1548 gboolean headers_only, ignore_limit;
1550 info = (UpdateAccountInfo *) user_data;
1551 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1552 mgr = modest_runtime_get_account_mgr ();
1554 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1555 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1557 if (canceled || err) {
1558 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1560 priv->error = g_error_copy (err);
1562 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1563 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1566 tny_folder_remove_observer (inbox, info->inbox_observer);
1567 g_object_unref (info->inbox_observer);
1568 info->inbox_observer = NULL;
1570 /* Notify the user about the error and then exit */
1571 update_account_notify_user_and_free (info, NULL);
1576 /* Try to send anyway */
1580 /* Get the message max size */
1581 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1582 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1584 max_size = G_MAXINT;
1586 max_size = max_size * KB;
1588 /* Create the new headers array. We need it to sort the
1589 new headers by date */
1590 new_headers_array = g_ptr_array_new ();
1591 if (info->inbox_observer) {
1592 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1593 while (!tny_iterator_is_done (new_headers_iter)) {
1594 TnyHeader *header = NULL;
1596 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1597 /* Apply per-message size limits */
1598 if (tny_header_get_message_size (header) < max_size)
1599 g_ptr_array_add (new_headers_array, g_object_ref (header));
1601 g_object_unref (header);
1602 tny_iterator_next (new_headers_iter);
1604 g_object_unref (new_headers_iter);
1606 tny_folder_remove_observer (inbox, info->inbox_observer);
1607 g_object_unref (info->inbox_observer);
1608 info->inbox_observer = NULL;
1611 if (new_headers_array->len == 0) {
1612 g_ptr_array_free (new_headers_array, FALSE);
1616 /* Get per-account message amount retrieval limit */
1617 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1618 if (retrieve_limit == 0)
1619 retrieve_limit = G_MAXINT;
1621 /* Get per-account retrieval type */
1622 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1623 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1626 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1628 /* Ask the users if they want to retrieve all the messages
1629 even though the limit was exceeded */
1630 ignore_limit = FALSE;
1631 if (new_headers_array->len > retrieve_limit) {
1632 /* Ask the user if a callback has been specified and
1633 if the mail operation has a source (this means that
1634 was invoked by the user and not automatically by a
1636 if (info->retrieve_all_cb && priv->source)
1637 ignore_limit = info->retrieve_all_cb (priv->source,
1638 new_headers_array->len,
1642 /* Copy the headers to a list and free the array */
1643 new_headers = tny_simple_list_new ();
1644 for (i=0; i < new_headers_array->len; i++) {
1645 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1646 tny_list_append (new_headers, G_OBJECT (header));
1648 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1649 g_ptr_array_free (new_headers_array, FALSE);
1651 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1654 GetMsgInfo *msg_info;
1658 priv->total = tny_list_get_length (new_headers);
1660 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1662 iter = tny_list_create_iterator (new_headers);
1664 /* Create the message info */
1665 msg_info = g_slice_new0 (GetMsgInfo);
1666 msg_info->mail_op = g_object_ref (info->mail_op);
1667 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1668 msg_info->more_msgs = g_object_ref (iter);
1669 msg_info->user_data = info;
1671 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1672 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1673 TnyFolder *folder = tny_header_get_folder (header);
1675 /* Get message in an async way */
1676 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1679 g_object_unref (folder);
1682 tny_iterator_next (iter);
1684 g_object_unref (iter);
1686 /* The mail operation will finish when the last
1687 message is retrieved */
1691 /* If we don't have to retrieve the new messages then
1693 update_account_send_mail (info);
1695 /* Check if the operation was a success */
1697 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1699 /* Call the user callback and free */
1700 update_account_notify_user_and_free (info, new_headers);
1704 inbox_refresh_status_update (GObject *obj,
1708 UpdateAccountInfo *info = NULL;
1709 ModestMailOperation *self = NULL;
1710 ModestMailOperationPrivate *priv = NULL;
1711 ModestMailOperationState *state;
1713 g_return_if_fail (user_data != NULL);
1714 g_return_if_fail (status != NULL);
1716 /* Show only the status information we want */
1717 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1720 info = (UpdateAccountInfo *) user_data;
1721 self = info->mail_op;
1722 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1724 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1726 priv->done = status->position;
1727 priv->total = status->of_total;
1729 state = modest_mail_operation_clone_state (self);
1731 /* This is not a GDK lock because we are a Tinymail callback and
1732 * Tinymail already acquires the Gdk lock */
1733 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1735 g_slice_free (ModestMailOperationState, state);
1739 recurse_folders_async_cb (TnyFolderStore *folder_store,
1745 UpdateAccountInfo *info;
1746 ModestMailOperationPrivate *priv;
1748 info = (UpdateAccountInfo *) user_data;
1749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1751 if (err || canceled) {
1752 /* If the error was previosly set by another callback
1753 don't set it again */
1755 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1757 priv->error = g_error_copy (err);
1759 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1760 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1764 /* We're not getting INBOX children if we don't want to poke all */
1765 TnyIterator *iter = tny_list_create_iterator (list);
1766 while (!tny_iterator_is_done (iter)) {
1767 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1769 /* Add to the list of all folders */
1770 tny_list_append (info->folders, (GObject *) folder);
1772 if (info->poke_all) {
1773 TnyList *folders = tny_simple_list_new ();
1774 /* Add pending call */
1775 info->pending_calls++;
1777 tny_folder_store_get_folders_async (folder, folders, NULL,
1778 recurse_folders_async_cb,
1780 g_object_unref (folders);
1783 g_object_unref (G_OBJECT (folder));
1785 tny_iterator_next (iter);
1787 g_object_unref (G_OBJECT (iter));
1790 /* Remove my own pending call */
1791 info->pending_calls--;
1793 /* This means that we have all the folders */
1794 if (info->pending_calls == 0) {
1795 TnyIterator *iter_all_folders;
1796 TnyFolder *inbox = NULL;
1798 /* If there was any error do not continue */
1800 update_account_notify_user_and_free (info, NULL);
1804 iter_all_folders = tny_list_create_iterator (info->folders);
1806 /* Do a poke status over all folders */
1807 while (!tny_iterator_is_done (iter_all_folders) &&
1808 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1809 TnyFolder *folder = NULL;
1811 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1813 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1814 /* Get a reference to the INBOX */
1815 inbox = g_object_ref (folder);
1817 /* Issue a poke status over the folder */
1819 tny_folder_poke_status (folder);
1822 /* Free and go to next */
1823 g_object_unref (folder);
1824 tny_iterator_next (iter_all_folders);
1826 g_object_unref (iter_all_folders);
1828 /* Refresh the INBOX */
1830 /* Refresh the folder. Our observer receives
1831 * the new emails during folder refreshes, so
1832 * we can use observer->new_headers
1834 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1835 tny_folder_add_observer (inbox, info->inbox_observer);
1837 /* Refresh the INBOX */
1838 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1839 g_object_unref (inbox);
1841 /* We could not perform the inbox refresh but
1842 we'll try to send mails anyway */
1843 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1849 modest_mail_operation_update_account (ModestMailOperation *self,
1850 const gchar *account_name,
1852 gboolean interactive,
1853 RetrieveAllCallback retrieve_all_cb,
1854 UpdateAccountCallback callback,
1857 UpdateAccountInfo *info = NULL;
1858 ModestMailOperationPrivate *priv = NULL;
1859 ModestTnyAccountStore *account_store = NULL;
1861 ModestMailOperationState *state;
1863 /* Init mail operation */
1864 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1867 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1868 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1870 /* Get the store account */
1871 account_store = modest_runtime_get_account_store ();
1873 modest_tny_account_store_get_server_account (account_store,
1875 TNY_ACCOUNT_TYPE_STORE);
1877 /* The above function could return NULL */
1878 if (!priv->account) {
1879 /* Check if the operation was a success */
1880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1881 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1885 /* Call the user callback */
1887 callback (self, NULL, user_data);
1889 /* Notify about operation end */
1890 modest_mail_operation_notify_end (self);
1895 /* We have once seen priv->account getting finalized during this code,
1896 * therefore adding a reference (bug #82296) */
1898 g_object_ref (priv->account);
1900 /* Create the helper object */
1901 info = g_slice_new0 (UpdateAccountInfo);
1902 info->pending_calls = 1;
1903 info->folders = tny_simple_list_new ();
1904 info->mail_op = g_object_ref (self);
1905 info->poke_all = poke_all;
1906 info->interactive = interactive;
1907 info->account_name = g_strdup (account_name);
1908 info->callback = callback;
1909 info->user_data = user_data;
1910 info->retrieve_all_cb = retrieve_all_cb;
1912 /* Set account busy */
1913 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1914 modest_mail_operation_notify_start (self);
1916 /* notify about the start of the operation */
1917 state = modest_mail_operation_clone_state (self);
1921 /* Start notifying progress */
1922 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1923 g_slice_free (ModestMailOperationState, state);
1925 /* Get all folders and continue in the callback */
1926 folders = tny_simple_list_new ();
1927 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1929 recurse_folders_async_cb,
1931 g_object_unref (folders);
1933 g_object_unref (priv->account);
1938 * Used to notify the queue from the main
1939 * loop. We call it inside an idle call to achieve that
1942 idle_notify_queue (gpointer data)
1944 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1946 gdk_threads_enter ();
1947 modest_mail_operation_notify_end (mail_op);
1948 gdk_threads_leave ();
1949 g_object_unref (mail_op);
1955 compare_headers_by_date (gconstpointer a,
1958 TnyHeader **header1, **header2;
1959 time_t sent1, sent2;
1961 header1 = (TnyHeader **) a;
1962 header2 = (TnyHeader **) b;
1964 sent1 = tny_header_get_date_sent (*header1);
1965 sent2 = tny_header_get_date_sent (*header2);
1967 /* We want the most recent ones (greater time_t) at the
1976 /* ******************************************************************* */
1977 /* ************************** STORE ACTIONS ************************* */
1978 /* ******************************************************************* */
1981 ModestMailOperation *mail_op;
1982 CreateFolderUserCallback callback;
1988 create_folder_cb (TnyFolderStore *parent_folder,
1990 TnyFolder *new_folder,
1994 ModestMailOperationPrivate *priv;
1995 CreateFolderInfo *info;
1997 info = (CreateFolderInfo *) user_data;
1998 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2000 if (canceled || err) {
2001 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2003 priv->error = g_error_copy (err);
2005 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2006 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2009 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2012 /* The user will unref the new_folder */
2014 info->callback (info->mail_op, parent_folder,
2015 new_folder, info->user_data);
2017 /* Notify about operation end */
2018 modest_mail_operation_notify_end (info->mail_op);
2021 g_object_unref (info->mail_op);
2022 g_slice_free (CreateFolderInfo, info);
2026 modest_mail_operation_create_folder (ModestMailOperation *self,
2027 TnyFolderStore *parent,
2029 CreateFolderUserCallback callback,
2032 ModestMailOperationPrivate *priv;
2034 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2035 g_return_if_fail (name);
2037 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2038 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2039 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2040 g_object_ref (parent) :
2041 modest_tny_folder_get_account (TNY_FOLDER (parent));
2043 /* Check for already existing folder */
2044 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2047 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2048 _CS("ckdg_ib_folder_already_exists"));
2052 if (TNY_IS_FOLDER (parent)) {
2053 /* Check folder rules */
2054 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2055 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2056 /* Set status failed and set an error */
2057 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2059 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2060 _("mail_in_ui_folder_create_error"));
2064 if (!strcmp (name, " ") || strchr (name, '/')) {
2065 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2066 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2067 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2068 _("mail_in_ui_folder_create_error"));
2072 CreateFolderInfo *info;
2074 info = g_slice_new0 (CreateFolderInfo);
2075 info->mail_op = g_object_ref (self);
2076 info->callback = callback;
2077 info->user_data = user_data;
2079 modest_mail_operation_notify_start (self);
2081 /* Create the folder */
2082 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2085 /* Call the user callback anyway */
2087 callback (self, parent, NULL, user_data);
2088 /* Notify about operation end */
2089 modest_mail_operation_notify_end (self);
2094 modest_mail_operation_remove_folder (ModestMailOperation *self,
2096 gboolean remove_to_trash)
2098 ModestMailOperationPrivate *priv;
2099 ModestTnyFolderRules rules;
2101 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2102 g_return_if_fail (TNY_IS_FOLDER (folder));
2104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2106 /* Check folder rules */
2107 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2108 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2109 /* Set status failed and set an error */
2110 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2111 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2112 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2113 _("mail_in_ui_folder_delete_error"));
2117 /* Get the account */
2118 priv->account = modest_tny_folder_get_account (folder);
2119 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2121 /* Delete folder or move to trash */
2122 if (remove_to_trash) {
2123 TnyFolder *trash_folder = NULL;
2124 trash_folder = modest_tny_account_get_special_folder (priv->account,
2125 TNY_FOLDER_TYPE_TRASH);
2126 /* TODO: error_handling */
2128 modest_mail_operation_notify_start (self);
2129 modest_mail_operation_xfer_folder (self, folder,
2130 TNY_FOLDER_STORE (trash_folder),
2132 g_object_unref (trash_folder);
2134 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2137 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2139 modest_mail_operation_notify_start (self);
2140 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2141 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2144 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2146 g_object_unref (parent);
2148 g_warning ("%s: could not get parent folder", __FUNCTION__);
2152 /* Notify about operation end */
2153 modest_mail_operation_notify_end (self);
2157 transfer_folder_status_cb (GObject *obj,
2161 ModestMailOperation *self;
2162 ModestMailOperationPrivate *priv;
2163 ModestMailOperationState *state;
2164 XFerFolderAsyncHelper *helper;
2166 g_return_if_fail (status != NULL);
2168 /* Show only the status information we want */
2169 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2172 helper = (XFerFolderAsyncHelper *) user_data;
2173 g_return_if_fail (helper != NULL);
2175 self = helper->mail_op;
2176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2178 priv->done = status->position;
2179 priv->total = status->of_total;
2181 state = modest_mail_operation_clone_state (self);
2183 /* This is not a GDK lock because we are a Tinymail callback
2184 * which is already GDK locked by Tinymail */
2186 /* no gdk_threads_enter (), CHECKED */
2188 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2190 /* no gdk_threads_leave (), CHECKED */
2192 g_slice_free (ModestMailOperationState, state);
2197 transfer_folder_cb (TnyFolder *folder,
2199 TnyFolderStore *into,
2200 TnyFolder *new_folder,
2204 XFerFolderAsyncHelper *helper;
2205 ModestMailOperation *self = NULL;
2206 ModestMailOperationPrivate *priv = NULL;
2208 helper = (XFerFolderAsyncHelper *) user_data;
2209 g_return_if_fail (helper != NULL);
2211 self = helper->mail_op;
2212 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2215 priv->error = g_error_copy (err);
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2218 } else if (cancelled) {
2219 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2220 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2221 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2222 _("Transference of %s was cancelled."),
2223 tny_folder_get_name (folder));
2226 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2229 /* Notify about operation end */
2230 modest_mail_operation_notify_end (self);
2232 /* If user defined callback function was defined, call it */
2233 if (helper->user_callback) {
2235 /* This is not a GDK lock because we are a Tinymail callback
2236 * which is already GDK locked by Tinymail */
2238 /* no gdk_threads_enter (), CHECKED */
2239 helper->user_callback (self, new_folder, helper->user_data);
2240 /* no gdk_threads_leave () , CHECKED */
2244 g_object_unref (helper->mail_op);
2245 g_slice_free (XFerFolderAsyncHelper, helper);
2250 * This function checks if the new name is a valid name for our local
2251 * folders account. The new name could not be the same than then name
2252 * of any of the mandatory local folders
2254 * We can not rely on tinymail because tinymail does not check the
2255 * name of the virtual folders that the account could have in the case
2256 * that we're doing a rename (because it directly calls Camel which
2257 * knows nothing about our virtual folders).
2259 * In the case of an actual copy/move (i.e. move/copy a folder between
2260 * accounts) tinymail uses the tny_folder_store_create_account which
2261 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2262 * checks the new name of the folder, so this call in that case
2263 * wouldn't be needed. *But* NOTE that if tinymail changes its
2264 * implementation (if folder transfers within the same account is no
2265 * longer implemented as a rename) this call will allow Modest to work
2268 * If the new name is not valid, this function will set the status to
2269 * failed and will set also an error in the mail operation
2272 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2273 TnyFolderStore *into,
2274 const gchar *new_name)
2276 if (TNY_IS_ACCOUNT (into) &&
2277 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2278 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2280 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2281 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2282 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2283 _CS("ckdg_ib_folder_already_exists"));
2290 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2292 TnyFolderStore *parent,
2293 gboolean delete_original,
2294 XferFolderAsyncUserCallback user_callback,
2297 ModestMailOperationPrivate *priv = NULL;
2298 ModestTnyFolderRules parent_rules = 0, rules;
2299 XFerFolderAsyncHelper *helper = NULL;
2300 const gchar *folder_name = NULL;
2301 const gchar *error_msg;
2303 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2304 g_return_if_fail (TNY_IS_FOLDER (folder));
2305 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2308 folder_name = tny_folder_get_name (folder);
2310 /* Set the error msg */
2311 error_msg = _("mail_in_ui_folder_move_target_error");
2313 /* Get account and set it into mail_operation */
2314 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2315 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2316 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2318 /* Get folder rules */
2319 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2320 if (TNY_IS_FOLDER (parent))
2321 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2323 /* Apply operation constraints */
2324 if ((gpointer) parent == (gpointer) folder ||
2325 (!TNY_IS_FOLDER_STORE (parent)) ||
2326 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2329 } else if (TNY_IS_FOLDER (parent) &&
2330 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2334 } else if (TNY_IS_FOLDER (parent) &&
2335 TNY_IS_FOLDER_STORE (folder) &&
2336 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2337 TNY_FOLDER_STORE (folder))) {
2338 /* Do not move a parent into a child */
2340 } else if (TNY_IS_FOLDER_STORE (parent) &&
2341 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2342 /* Check that the new folder name is not used by any
2345 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2346 /* Check that the new folder name is not used by any
2347 special local folder */
2350 /* Create the helper */
2351 helper = g_slice_new0 (XFerFolderAsyncHelper);
2352 helper->mail_op = g_object_ref (self);
2353 helper->user_callback = user_callback;
2354 helper->user_data = user_data;
2356 /* Move/Copy folder */
2357 modest_mail_operation_notify_start (self);
2358 tny_folder_copy_async (folder,
2360 tny_folder_get_name (folder),
2363 transfer_folder_status_cb,
2369 /* Set status failed and set an error */
2370 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2371 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2372 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2375 /* Call the user callback if exists */
2377 user_callback (self, NULL, user_data);
2379 /* Notify the queue */
2380 modest_mail_operation_notify_end (self);
2384 modest_mail_operation_rename_folder (ModestMailOperation *self,
2387 XferFolderAsyncUserCallback user_callback,
2390 ModestMailOperationPrivate *priv;
2391 ModestTnyFolderRules rules;
2392 XFerFolderAsyncHelper *helper;
2394 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2395 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2396 g_return_if_fail (name);
2398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2400 /* Get account and set it into mail_operation */
2401 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2402 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2404 /* Check folder rules */
2405 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2406 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2408 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2411 TnyFolderStore *into;
2413 into = tny_folder_get_folder_store (folder);
2415 /* Check that the new folder name is not used by any
2416 special local folder */
2417 if (new_name_valid_if_local_account (priv, into, name)) {
2418 /* Create the helper */
2419 helper = g_slice_new0 (XFerFolderAsyncHelper);
2420 helper->mail_op = g_object_ref(self);
2421 helper->user_callback = user_callback;
2422 helper->user_data = user_data;
2424 /* Rename. Camel handles folder subscription/unsubscription */
2425 modest_mail_operation_notify_start (self);
2426 tny_folder_copy_async (folder, into, name, TRUE,
2428 transfer_folder_status_cb,
2430 g_object_unref (into);
2432 g_object_unref (into);
2439 /* Set status failed and set an error */
2440 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2441 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2442 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2443 _("FIXME: unable to rename"));
2446 user_callback (self, NULL, user_data);
2448 /* Notify about operation end */
2449 modest_mail_operation_notify_end (self);
2452 /* ******************************************************************* */
2453 /* ************************** MSG ACTIONS ************************* */
2454 /* ******************************************************************* */
2457 modest_mail_operation_get_msg (ModestMailOperation *self,
2459 gboolean progress_feedback,
2460 GetMsgAsyncUserCallback user_callback,
2463 GetMsgInfo *helper = NULL;
2465 ModestMailOperationPrivate *priv;
2467 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2468 g_return_if_fail (TNY_IS_HEADER (header));
2470 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2471 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2475 /* Check memory low */
2476 if (_check_memory_low (self)) {
2478 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2479 modest_mail_operation_notify_end (self);
2483 /* Get account and set it into mail_operation */
2484 folder = tny_header_get_folder (header);
2485 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2487 /* Check for cached messages */
2488 if (progress_feedback) {
2489 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2490 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2492 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2494 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2497 /* Create the helper */
2498 helper = g_slice_new0 (GetMsgInfo);
2499 helper->header = g_object_ref (header);
2500 helper->mail_op = g_object_ref (self);
2501 helper->user_callback = user_callback;
2502 helper->user_data = user_data;
2503 helper->destroy_notify = NULL;
2504 helper->last_total_bytes = 0;
2505 helper->sum_total_bytes = 0;
2506 helper->total_bytes = tny_header_get_message_size (header);
2507 helper->more_msgs = NULL;
2509 modest_mail_operation_notify_start (self);
2511 /* notify about the start of the operation */
2512 ModestMailOperationState *state;
2513 state = modest_mail_operation_clone_state (self);
2516 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2518 g_slice_free (ModestMailOperationState, state);
2520 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2522 g_object_unref (G_OBJECT (folder));
2526 get_msg_status_cb (GObject *obj,
2530 GetMsgInfo *helper = NULL;
2532 g_return_if_fail (status != NULL);
2534 /* Show only the status information we want */
2535 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2538 helper = (GetMsgInfo *) user_data;
2539 g_return_if_fail (helper != NULL);
2541 /* Notify progress */
2542 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2543 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2547 get_msg_async_cb (TnyFolder *folder,
2553 GetMsgInfo *info = NULL;
2554 ModestMailOperationPrivate *priv = NULL;
2557 info = (GetMsgInfo *) user_data;
2559 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2562 if (info->more_msgs) {
2563 tny_iterator_next (info->more_msgs);
2564 finished = (tny_iterator_is_done (info->more_msgs));
2566 finished = (priv->done == priv->total) ? TRUE : FALSE;
2569 /* If canceled by the user, ignore the error given by Tinymail */
2573 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2575 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2577 priv->error = g_error_copy ((const GError *) err);
2578 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2581 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2582 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2585 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2586 /* Set the success status before calling the user callback */
2587 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2591 /* Call the user callback */
2592 if (info->user_callback)
2593 info->user_callback (info->mail_op, info->header, canceled,
2594 msg, err, info->user_data);
2596 /* Notify about operation end if this is the last callback */
2598 /* Free user data */
2599 if (info->destroy_notify)
2600 info->destroy_notify (info->user_data);
2602 /* Notify about operation end */
2603 modest_mail_operation_notify_end (info->mail_op);
2606 if (info->more_msgs)
2607 g_object_unref (info->more_msgs);
2608 g_object_unref (info->header);
2609 g_object_unref (info->mail_op);
2610 g_slice_free (GetMsgInfo, info);
2611 } else if (info->more_msgs) {
2612 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2613 TnyFolder *folder = tny_header_get_folder (header);
2615 g_object_unref (info->header);
2616 info->header = g_object_ref (header);
2618 /* Retrieve the next message */
2619 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2621 g_object_unref (header);
2622 g_object_unref (folder);
2624 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2629 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2630 TnyList *header_list,
2631 GetMsgAsyncUserCallback user_callback,
2633 GDestroyNotify notify)
2635 ModestMailOperationPrivate *priv = NULL;
2637 TnyIterator *iter = NULL;
2638 gboolean has_uncached_messages;
2640 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2642 /* Init mail operation */
2643 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2644 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2646 priv->total = tny_list_get_length(header_list);
2648 /* Check memory low */
2649 if (_check_memory_low (self)) {
2650 if (user_callback) {
2651 TnyHeader *header = NULL;
2654 if (tny_list_get_length (header_list) > 0) {
2655 iter = tny_list_create_iterator (header_list);
2656 header = (TnyHeader *) tny_iterator_get_current (iter);
2657 g_object_unref (iter);
2659 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2661 g_object_unref (header);
2665 /* Notify about operation end */
2666 modest_mail_operation_notify_end (self);
2670 /* Check uncached messages */
2671 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2672 !has_uncached_messages && !tny_iterator_is_done (iter);
2673 tny_iterator_next (iter)) {
2676 header = (TnyHeader *) tny_iterator_get_current (iter);
2677 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2678 has_uncached_messages = TRUE;
2679 g_object_unref (header);
2681 g_object_unref (iter);
2682 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2684 /* Get account and set it into mail_operation */
2685 if (tny_list_get_length (header_list) >= 1) {
2686 TnyIterator *iterator = tny_list_create_iterator (header_list);
2687 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2689 TnyFolder *folder = tny_header_get_folder (header);
2691 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2692 g_object_unref (folder);
2694 g_object_unref (header);
2696 g_object_unref (iterator);
2699 msg_list_size = compute_message_list_size (header_list, 0);
2701 modest_mail_operation_notify_start (self);
2702 iter = tny_list_create_iterator (header_list);
2703 if (!tny_iterator_is_done (iter)) {
2704 /* notify about the start of the operation */
2705 ModestMailOperationState *state;
2706 state = modest_mail_operation_clone_state (self);
2709 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2712 GetMsgInfo *msg_info = NULL;
2713 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2714 TnyFolder *folder = tny_header_get_folder (header);
2716 /* Create the message info */
2717 msg_info = g_slice_new0 (GetMsgInfo);
2718 msg_info->mail_op = g_object_ref (self);
2719 msg_info->header = g_object_ref (header);
2720 msg_info->more_msgs = g_object_ref (iter);
2721 msg_info->user_callback = user_callback;
2722 msg_info->user_data = user_data;
2723 msg_info->destroy_notify = notify;
2724 msg_info->last_total_bytes = 0;
2725 msg_info->sum_total_bytes = 0;
2726 msg_info->total_bytes = msg_list_size;
2728 /* The callback will call it per each header */
2729 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2731 /* Free and go on */
2732 g_object_unref (header);
2733 g_object_unref (folder);
2734 g_slice_free (ModestMailOperationState, state);
2736 g_object_unref (iter);
2741 remove_msgs_async_cb (TnyFolder *folder,
2746 gboolean expunge, leave_on_server;
2747 const gchar *account_name;
2749 TnyAccount *account;
2750 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2751 ModestMailOperation *self;
2752 ModestMailOperationPrivate *priv;
2754 self = (ModestMailOperation *) user_data;
2755 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2757 if (canceled || err) {
2758 /* If canceled by the user, ignore the error given by Tinymail */
2760 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2762 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2763 priv->error = g_error_copy ((const GError *) err);
2764 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2767 modest_mail_operation_notify_end (self);
2768 g_object_unref (self);
2772 account = tny_folder_get_account (folder);
2773 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2775 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2777 proto = tny_account_get_proto (account);
2778 g_object_unref (account);
2781 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2783 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2784 modest_tny_folder_is_remote_folder (folder) == FALSE)
2790 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2795 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2797 gboolean remove_to_trash /*ignored*/)
2799 TnyFolder *folder = NULL;
2800 ModestMailOperationPrivate *priv;
2801 TnyIterator *iter = NULL;
2802 TnyHeader *header = NULL;
2803 TnyList *remove_headers = NULL;
2804 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2806 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2807 g_return_if_fail (TNY_IS_LIST (headers));
2809 if (remove_to_trash)
2810 g_warning ("remove to trash is not implemented");
2812 if (tny_list_get_length(headers) == 0) {
2813 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2814 goto cleanup; /* nothing to do */
2817 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2818 remove_headers = g_object_ref(headers);
2820 /* Get folder from first header and sync it */
2821 iter = tny_list_create_iterator (headers);
2822 header = TNY_HEADER (tny_iterator_get_current (iter));
2824 folder = tny_header_get_folder (header);
2825 if (!TNY_IS_FOLDER(folder)) {
2826 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2830 /* Don't remove messages that are being sent */
2831 if (modest_tny_folder_is_local_folder (folder)) {
2832 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2834 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2835 TnyTransportAccount *traccount = NULL;
2836 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2837 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2839 ModestTnySendQueueStatus status;
2840 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2842 if (TNY_IS_SEND_QUEUE (send_queue)) {
2843 TnyIterator *iter = tny_list_create_iterator(headers);
2844 g_object_unref(remove_headers);
2845 remove_headers = TNY_LIST(tny_simple_list_new());
2846 while (!tny_iterator_is_done(iter)) {
2848 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2849 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2850 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2851 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2852 tny_list_append(remove_headers, G_OBJECT(hdr));
2854 g_object_unref(hdr);
2856 tny_iterator_next(iter);
2858 g_object_unref(iter);
2860 g_object_unref(traccount);
2864 /* Get account and set it into mail_operation */
2865 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2866 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2867 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2869 /* remove message from folder */
2870 modest_mail_operation_notify_start (self);
2871 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2872 NULL, g_object_ref (self));
2876 g_object_unref (remove_headers);
2878 g_object_unref (header);
2880 g_object_unref (iter);
2882 g_object_unref (folder);
2886 notify_progress_of_multiple_messages (ModestMailOperation *self,
2888 gint *last_total_bytes,
2889 gint *sum_total_bytes,
2891 gboolean increment_done)
2893 ModestMailOperationPrivate *priv;
2894 ModestMailOperationState *state;
2895 gboolean is_num_bytes = FALSE;
2897 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2899 /* We know that tinymail sends us information about
2900 * transferred bytes with this particular message
2902 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2903 * I just added the 'if' so we don't get runtime warning)
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;
3092 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3093 g_return_if_fail (headers && TNY_IS_LIST (headers));
3094 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3097 priv->total = tny_list_get_length (headers);
3099 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3100 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3102 /* Apply folder rules */
3103 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3104 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3105 /* Set status failed and set an error */
3106 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3108 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3109 _CS("ckct_ib_unable_to_paste_here"));
3110 /* Notify the queue */
3111 modest_mail_operation_notify_end (self);
3115 /* Get source folder */
3116 iter = tny_list_create_iterator (headers);
3117 header = TNY_HEADER (tny_iterator_get_current (iter));
3119 src_folder = tny_header_get_folder (header);
3120 g_object_unref (header);
3122 g_object_unref (iter);
3124 if (src_folder == NULL) {
3125 /* Notify the queue */
3126 modest_mail_operation_notify_end (self);
3128 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3133 /* Check folder source and destination */
3134 if (src_folder == folder) {
3135 /* Set status failed and set an error */
3136 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3137 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3138 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3139 _("mail_in_ui_folder_copy_target_error"));
3141 /* Notify the queue */
3142 modest_mail_operation_notify_end (self);
3145 g_object_unref (src_folder);
3149 /* Create the helper */
3150 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3151 helper->mail_op = g_object_ref(self);
3152 helper->dest_folder = g_object_ref(folder);
3153 helper->user_callback = user_callback;
3154 helper->user_data = user_data;
3155 helper->last_total_bytes = 0;
3156 helper->sum_total_bytes = 0;
3157 helper->total_bytes = compute_message_list_size (headers, 0);
3159 /* Get account and set it into mail_operation */
3160 priv->account = modest_tny_folder_get_account (src_folder);
3161 dst_account = modest_tny_folder_get_account (folder);
3163 if (priv->account == dst_account) {
3164 /* Transfer all messages at once using the fast
3165 * method. Note that depending on the server this
3166 * might not be that fast, and might not be
3167 * user-cancellable either */
3168 helper->headers = g_object_ref (headers);
3169 helper->more_msgs = NULL;
3171 /* Transfer messages one by one so the user can cancel
3174 helper->headers = tny_simple_list_new ();
3175 helper->more_msgs = tny_list_create_iterator (headers);
3176 hdr = tny_iterator_get_current (helper->more_msgs);
3177 tny_list_append (helper->headers, hdr);
3178 g_object_unref (hdr);
3181 /* If leave_on_server is set to TRUE then don't use
3182 delete_original, we always pass FALSE. This is because
3183 otherwise tinymail will try to sync the source folder and
3184 this could cause an error if we're offline while
3185 transferring an already downloaded message from a POP
3187 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3188 MODEST_PROTOCOL_STORE_POP) {
3189 const gchar *account_name;
3191 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3192 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3195 leave_on_server = FALSE;
3198 /* Do not delete messages if leave on server is TRUE */
3199 helper->delete = (leave_on_server) ? FALSE : delete_original;
3201 modest_mail_operation_notify_start (self);
3203 /* Start notifying progress */
3204 state = modest_mail_operation_clone_state (self);
3207 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3208 g_slice_free (ModestMailOperationState, state);
3210 tny_folder_transfer_msgs_async (src_folder,
3215 transfer_msgs_status_cb,
3217 g_object_unref (src_folder);
3218 g_object_unref (dst_account);
3223 on_refresh_folder (TnyFolder *folder,
3228 RefreshAsyncHelper *helper = NULL;
3229 ModestMailOperation *self = NULL;
3230 ModestMailOperationPrivate *priv = NULL;
3232 helper = (RefreshAsyncHelper *) user_data;
3233 self = helper->mail_op;
3234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3236 g_return_if_fail(priv!=NULL);
3239 priv->error = g_error_copy (error);
3240 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3245 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3246 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3247 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3248 _("Error trying to refresh the contents of %s"),
3249 tny_folder_get_name (folder));
3253 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3256 /* Call user defined callback, if it exists */
3257 if (helper->user_callback) {
3259 /* This is not a GDK lock because we are a Tinymail callback and
3260 * Tinymail already acquires the Gdk lock */
3261 helper->user_callback (self, folder, helper->user_data);
3265 g_slice_free (RefreshAsyncHelper, helper);
3267 /* Notify about operation end */
3268 modest_mail_operation_notify_end (self);
3269 g_object_unref(self);
3273 on_refresh_folder_status_update (GObject *obj,
3277 RefreshAsyncHelper *helper = NULL;
3278 ModestMailOperation *self = NULL;
3279 ModestMailOperationPrivate *priv = NULL;
3280 ModestMailOperationState *state;
3282 g_return_if_fail (user_data != NULL);
3283 g_return_if_fail (status != NULL);
3285 /* Show only the status information we want */
3286 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3289 helper = (RefreshAsyncHelper *) user_data;
3290 self = helper->mail_op;
3291 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3293 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3295 priv->done = status->position;
3296 priv->total = status->of_total;
3298 state = modest_mail_operation_clone_state (self);
3300 /* This is not a GDK lock because we are a Tinymail callback and
3301 * Tinymail already acquires the Gdk lock */
3302 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3304 g_slice_free (ModestMailOperationState, state);
3308 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3310 RefreshAsyncUserCallback user_callback,
3313 ModestMailOperationPrivate *priv = NULL;
3314 RefreshAsyncHelper *helper = NULL;
3316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3318 /* Check memory low */
3319 if (_check_memory_low (self)) {
3321 user_callback (self, folder, user_data);
3322 /* Notify about operation end */
3323 modest_mail_operation_notify_end (self);
3327 /* Get account and set it into mail_operation */
3328 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3329 priv->account = modest_tny_folder_get_account (folder);
3330 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3332 /* Create the helper */
3333 helper = g_slice_new0 (RefreshAsyncHelper);
3334 helper->mail_op = g_object_ref(self);
3335 helper->user_callback = user_callback;
3336 helper->user_data = user_data;
3338 modest_mail_operation_notify_start (self);
3340 /* notify that the operation was started */
3341 ModestMailOperationState *state;
3342 state = modest_mail_operation_clone_state (self);
3345 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3347 g_slice_free (ModestMailOperationState, state);
3349 tny_folder_refresh_async (folder,
3351 on_refresh_folder_status_update,
3356 run_queue_notify_and_destroy (RunQueueHelper *helper,
3357 ModestMailOperationStatus status)
3359 ModestMailOperationPrivate *priv;
3362 if (helper->error_handler &&
3363 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3364 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3365 if (helper->start_handler &&
3366 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3367 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3368 if (helper->stop_handler &&
3369 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3370 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3373 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3374 priv->status = status;
3377 modest_mail_operation_notify_end (helper->self);
3380 g_object_unref (helper->queue);
3381 g_object_unref (helper->self);
3382 g_slice_free (RunQueueHelper, helper);
3386 run_queue_stop (ModestTnySendQueue *queue,
3389 RunQueueHelper *helper;
3391 g_debug ("%s sending queue stopped", __FUNCTION__);
3393 helper = (RunQueueHelper *) user_data;
3394 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3398 modest_mail_operation_run_queue (ModestMailOperation *self,
3399 ModestTnySendQueue *queue)
3401 ModestMailOperationPrivate *priv;
3402 RunQueueHelper *helper;
3404 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3405 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3408 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3409 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3410 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3412 /* Create the helper */
3413 helper = g_slice_new0 (RunQueueHelper);
3414 helper->queue = g_object_ref (queue);
3415 helper->self = g_object_ref (self);
3416 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3417 G_CALLBACK (run_queue_stop),
3420 /* Notify operation has started */
3421 modest_mail_operation_notify_start (self);
3422 g_debug ("%s, run queue started", __FUNCTION__);
3426 sync_folder_finish_callback (TnyFolder *self,
3432 ModestMailOperation *mail_op;
3433 ModestMailOperationPrivate *priv;
3435 mail_op = (ModestMailOperation *) user_data;
3436 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3438 /* If canceled by the user, ignore the error given by Tinymail */
3440 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3442 /* If the operation was a sync then the status is
3443 failed, but if it's part of another operation then
3444 just set it as finished with errors */
3445 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3446 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3448 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3449 priv->error = g_error_copy ((const GError *) err);
3450 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3452 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3455 modest_mail_operation_notify_end (mail_op);
3456 g_object_unref (mail_op);
3460 modest_mail_operation_sync_folder (ModestMailOperation *self,
3461 TnyFolder *folder, gboolean expunge)
3463 ModestMailOperationPrivate *priv;
3465 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3466 g_return_if_fail (TNY_IS_FOLDER (folder));
3467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3469 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3470 priv->account = modest_tny_folder_get_account (folder);
3471 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3473 modest_mail_operation_notify_start (self);
3474 g_object_ref (self);
3475 tny_folder_sync_async (folder, expunge,
3476 (TnyFolderCallback) sync_folder_finish_callback,
3481 modest_mail_operation_notify_start (ModestMailOperation *self)
3483 ModestMailOperationPrivate *priv = NULL;
3485 g_return_if_fail (self);
3487 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3489 /* Ensure that all the fields are filled correctly */
3490 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3492 /* Notify the observers about the mail operation. We do not
3493 wrapp this emission because we assume that this function is
3494 always called from within the main lock */
3495 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3500 * It's used by the mail operation queue to notify the observers
3501 * attached to that signal that the operation finished. We need to use
3502 * that because tinymail does not give us the progress of a given
3503 * operation when it finishes (it directly calls the operation
3507 modest_mail_operation_notify_end (ModestMailOperation *self)
3509 ModestMailOperationPrivate *priv = NULL;
3511 g_return_if_fail (self);
3513 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3515 /* Notify the observers about the mail operation end. We do
3516 not wrapp this emission because we assume that this
3517 function is always called from within the main lock */
3518 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3520 /* Remove the error user data */
3521 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3522 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3526 modest_mail_operation_get_account (ModestMailOperation *self)
3528 ModestMailOperationPrivate *priv = NULL;
3530 g_return_val_if_fail (self, NULL);
3532 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3534 return (priv->account) ? g_object_ref (priv->account) : NULL;
3538 modest_mail_operation_noop (ModestMailOperation *self)
3540 ModestMailOperationPrivate *priv = NULL;
3542 g_return_if_fail (self);
3544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3545 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3546 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3550 /* This mail operation does nothing actually */
3551 modest_mail_operation_notify_start (self);
3552 modest_mail_operation_notify_end (self);
3557 modest_mail_operation_to_string (ModestMailOperation *self)
3559 const gchar *type, *status, *account_id;
3560 ModestMailOperationPrivate *priv = NULL;
3562 g_return_val_if_fail (self, NULL);
3564 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3566 /* new operations don't have anything interesting */
3567 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3568 return g_strdup_printf ("%p <new operation>", self);
3570 switch (priv->op_type) {
3571 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3572 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3573 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3574 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3575 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3576 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3577 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3578 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3579 default: type = "UNEXPECTED"; break;
3582 switch (priv->status) {
3583 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3584 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3585 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3586 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3587 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3588 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3589 default: status= "UNEXPECTED"; break;
3592 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3594 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3595 priv->done, priv->total,
3596 priv->error && priv->error->message ? priv->error->message : "");
3600 * Once the mail operations were objects this will be no longer
3601 * needed. I don't like it, but we need it for the moment
3604 _check_memory_low (ModestMailOperation *mail_op)
3606 if (modest_platform_check_memory_low (NULL, FALSE)) {
3607 ModestMailOperationPrivate *priv;
3609 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3610 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3611 g_set_error (&(priv->error),
3612 MODEST_MAIL_OPERATION_ERROR,
3613 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3614 "Not enough memory to complete the operation");