1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-error.h>
45 #include <tny-folder-observer.h>
46 #include <camel/camel-stream-mem.h>
47 #include <glib/gi18n.h>
48 #include <modest-defs.h>
49 #include "modest-platform.h"
50 #include "modest-account-mgr-helpers.h"
51 #include <modest-tny-account.h>
52 #include <modest-tny-send-queue.h>
53 #include <modest-runtime.h>
54 #include "modest-text-utils.h"
55 #include "modest-tny-msg.h"
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account-store.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-marshal.h"
60 #include "modest-error.h"
61 #include "modest-mail-operation.h"
62 #include <modest-count-stream.h>
63 #include <libgnomevfs/gnome-vfs.h>
64 #include "modest-utils.h"
65 #include "modest-debug.h"
66 #ifdef MODEST_USE_LIBTIME
67 #include <clockd/libtime.h>
69 #include "modest-account-protocol.h"
70 #include <camel/camel-stream-null.h>
71 #include <widgets/modest-msg-view-window.h>
76 * Remove all these #ifdef stuff when the tinymail's idle calls become
79 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
81 /* 'private'/'protected' functions */
82 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
83 static void modest_mail_operation_init (ModestMailOperation *obj);
84 static void modest_mail_operation_finalize (GObject *obj);
86 static void get_msg_async_cb (TnyFolder *folder,
92 static void get_msg_status_cb (GObject *obj,
96 static void modest_mail_operation_notify_start (ModestMailOperation *self);
97 static void modest_mail_operation_notify_end (ModestMailOperation *self);
99 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
101 gint *last_total_bytes,
102 gint *sum_total_bytes,
104 gboolean increment_done);
106 static guint compute_message_list_size (TnyList *headers, guint num_elements);
108 static int compare_headers_by_date (gconstpointer a,
111 static void sync_folder_finish_callback (TnyFolder *self,
116 static gboolean _check_memory_low (ModestMailOperation *mail_op);
120 ModestTnySendQueue *queue;
121 ModestMailOperation *self;
127 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
128 ModestMailOperationStatus status);
130 /* Helpers for the update account operation (send & receive)*/
133 ModestMailOperation *mail_op;
135 UpdateAccountCallback callback;
140 TnyFolderObserver *inbox_observer;
141 gboolean interactive;
143 gboolean update_folder_counts;
146 static void destroy_update_account_info (UpdateAccountInfo *info);
148 static void update_account_send_mail (UpdateAccountInfo *info);
150 static void update_account_get_msg_async_cb (TnyFolder *folder,
156 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
157 TnyList *new_headers);
159 enum _ModestMailOperationSignals
161 PROGRESS_CHANGED_SIGNAL,
162 OPERATION_STARTED_SIGNAL,
163 OPERATION_FINISHED_SIGNAL,
167 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
168 struct _ModestMailOperationPrivate {
174 ErrorCheckingUserCallback error_checking;
175 gpointer error_checking_user_data;
176 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
177 ModestMailOperationStatus status;
178 ModestMailOperationTypeOperation op_type;
181 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
182 MODEST_TYPE_MAIL_OPERATION, \
183 ModestMailOperationPrivate))
185 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
186 priv->status = new_status;\
191 GetMsgAsyncUserCallback user_callback;
193 TnyIterator *more_msgs;
195 ModestMailOperation *mail_op;
196 GDestroyNotify destroy_notify;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 TnyIterator *get_parts;
204 typedef struct _RefreshAsyncHelper {
205 ModestMailOperation *mail_op;
206 RefreshAsyncUserCallback user_callback;
208 } RefreshAsyncHelper;
210 typedef struct _XFerMsgsAsyncHelper
212 ModestMailOperation *mail_op;
214 TnyIterator *more_msgs;
215 TnyFolder *dest_folder;
216 XferMsgsAsyncUserCallback user_callback;
219 gint last_total_bytes;
220 gint sum_total_bytes;
222 } XFerMsgsAsyncHelper;
224 typedef struct _XFerFolderAsyncHelper
226 ModestMailOperation *mail_op;
227 XferFolderAsyncUserCallback user_callback;
229 } XFerFolderAsyncHelper;
231 typedef struct _SyncFolderHelper {
232 ModestMailOperation *mail_op;
233 SyncFolderCallback user_callback;
237 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
241 static void modest_mail_operation_create_msg (ModestMailOperation *self,
242 const gchar *from, const gchar *to,
243 const gchar *cc, const gchar *bcc,
244 const gchar *subject, const gchar *plain_body,
245 const gchar *html_body, const GList *attachments_list,
246 const GList *images_list,
247 TnyHeaderFlags priority_flags,
248 const gchar *references, const gchar *in_reply_to,
249 ModestMailOperationCreateMsgCallback callback,
252 static gboolean idle_notify_queue (gpointer data);
255 ModestMailOperation *mail_op;
265 GList *attachments_list;
267 TnyHeaderFlags priority_flags;
268 ModestMailOperationCreateMsgCallback callback;
274 ModestMailOperation *mail_op;
276 ModestMailOperationCreateMsgCallback callback;
281 static GObjectClass *parent_class = NULL;
283 static guint signals[NUM_SIGNALS] = {0};
286 modest_mail_operation_get_type (void)
288 static GType my_type = 0;
290 static const GTypeInfo my_info = {
291 sizeof(ModestMailOperationClass),
292 NULL, /* base init */
293 NULL, /* base finalize */
294 (GClassInitFunc) modest_mail_operation_class_init,
295 NULL, /* class finalize */
296 NULL, /* class data */
297 sizeof(ModestMailOperation),
299 (GInstanceInitFunc) modest_mail_operation_init,
302 my_type = g_type_register_static (G_TYPE_OBJECT,
303 "ModestMailOperation",
310 modest_mail_operation_class_init (ModestMailOperationClass *klass)
312 GObjectClass *gobject_class;
313 gobject_class = (GObjectClass*) klass;
315 parent_class = g_type_class_peek_parent (klass);
316 gobject_class->finalize = modest_mail_operation_finalize;
318 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
321 * ModestMailOperation::progress-changed
322 * @self: the #MailOperation that emits the signal
323 * @user_data: user data set when the signal handler was connected
325 * Emitted when the progress of a mail operation changes
327 signals[PROGRESS_CHANGED_SIGNAL] =
328 g_signal_new ("progress-changed",
329 G_TYPE_FROM_CLASS (gobject_class),
331 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
333 g_cclosure_marshal_VOID__POINTER,
334 G_TYPE_NONE, 1, G_TYPE_POINTER);
338 * This signal is issued whenever a mail operation starts, and
339 * starts mean when the tinymail operation is issued. This
340 * means that it could happen that something wrong happens and
341 * the tinymail function is never called. In this situation a
342 * operation-finished will be issued without any
345 signals[OPERATION_STARTED_SIGNAL] =
346 g_signal_new ("operation-started",
347 G_TYPE_FROM_CLASS (gobject_class),
349 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
351 g_cclosure_marshal_VOID__VOID,
356 * This signal is issued whenever a mail operation
357 * finishes. Note that this signal could be issued without any
358 * previous "operation-started" signal, because this last one
359 * is only issued when the tinymail operation is successfully
362 signals[OPERATION_FINISHED_SIGNAL] =
363 g_signal_new ("operation-finished",
364 G_TYPE_FROM_CLASS (gobject_class),
366 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
368 g_cclosure_marshal_VOID__VOID,
373 modest_mail_operation_init (ModestMailOperation *obj)
375 ModestMailOperationPrivate *priv;
377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
379 priv->account = NULL;
380 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
381 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
386 priv->error_checking = NULL;
387 priv->error_checking_user_data = NULL;
391 modest_mail_operation_finalize (GObject *obj)
393 ModestMailOperationPrivate *priv;
395 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
400 g_error_free (priv->error);
404 g_object_unref (priv->source);
408 g_object_unref (priv->account);
409 priv->account = NULL;
413 G_OBJECT_CLASS(parent_class)->finalize (obj);
417 modest_mail_operation_new (GObject *source)
419 ModestMailOperation *obj;
420 ModestMailOperationPrivate *priv;
422 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
426 priv->source = g_object_ref(source);
432 modest_mail_operation_new_with_error_handling (GObject *source,
433 ErrorCheckingUserCallback error_handler,
435 ErrorCheckingUserDataDestroyer error_handler_destroyer)
437 ModestMailOperation *obj;
438 ModestMailOperationPrivate *priv;
440 obj = modest_mail_operation_new (source);
441 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
443 g_return_val_if_fail (error_handler != NULL, obj);
444 priv->error_checking = error_handler;
445 priv->error_checking_user_data = user_data;
446 priv->error_checking_user_data_destroyer = error_handler_destroyer;
452 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
454 ModestMailOperationPrivate *priv;
456 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
461 /* Call the user callback */
462 if (priv->error_checking != NULL)
463 priv->error_checking (self, priv->error_checking_user_data);
467 ModestMailOperationTypeOperation
468 modest_mail_operation_get_type_operation (ModestMailOperation *self)
470 ModestMailOperationPrivate *priv;
472 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
473 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
475 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
477 return priv->op_type;
481 modest_mail_operation_is_mine (ModestMailOperation *self,
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
490 if (priv->source == NULL) return FALSE;
492 return priv->source == me;
496 modest_mail_operation_get_source (ModestMailOperation *self)
498 ModestMailOperationPrivate *priv;
500 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
505 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
509 return (priv->source) ? g_object_ref (priv->source) : NULL;
512 ModestMailOperationStatus
513 modest_mail_operation_get_status (ModestMailOperation *self)
515 ModestMailOperationPrivate *priv;
517 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
518 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
519 MODEST_MAIL_OPERATION_STATUS_INVALID);
521 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
524 return MODEST_MAIL_OPERATION_STATUS_INVALID;
531 modest_mail_operation_get_error (ModestMailOperation *self)
533 ModestMailOperationPrivate *priv;
535 g_return_val_if_fail (self, NULL);
536 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
538 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
541 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
549 modest_mail_operation_cancel (ModestMailOperation *self)
551 ModestMailOperationPrivate *priv;
552 gboolean canceled = FALSE;
554 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
556 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
559 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
561 /* Cancel the mail operation */
562 g_return_val_if_fail (priv->account, FALSE);
563 tny_account_cancel (priv->account);
565 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
566 ModestTnySendQueue *queue;
567 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
570 /* Cancel the sending of the following next messages */
571 if (TNY_IS_SEND_QUEUE (queue))
572 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
579 modest_mail_operation_get_task_done (ModestMailOperation *self)
581 ModestMailOperationPrivate *priv;
583 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
586 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
591 modest_mail_operation_get_task_total (ModestMailOperation *self)
593 ModestMailOperationPrivate *priv;
595 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
598 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
603 modest_mail_operation_is_finished (ModestMailOperation *self)
605 ModestMailOperationPrivate *priv;
606 gboolean retval = FALSE;
608 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
611 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
613 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
614 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
615 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
616 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
626 * Creates an image of the current state of a mail operation, the
627 * caller must free it
629 static ModestMailOperationState *
630 modest_mail_operation_clone_state (ModestMailOperation *self)
632 ModestMailOperationState *state;
633 ModestMailOperationPrivate *priv;
635 g_return_val_if_fail (self, NULL);
636 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
637 g_return_val_if_fail (priv, NULL);
642 state = g_slice_new (ModestMailOperationState);
644 state->status = priv->status;
645 state->op_type = priv->op_type;
646 state->done = priv->done;
647 state->total = priv->total;
648 state->finished = modest_mail_operation_is_finished (self);
649 state->bytes_done = 0;
650 state->bytes_total = 0;
655 /* ******************************************************************* */
656 /* ************************** SEND ACTIONS ************************* */
657 /* ******************************************************************* */
661 ModestMailOperation *mail_op;
666 send_mail_on_sync_async_cb (TnyFolder *folder,
671 ModestMailOperationPrivate *priv;
672 ModestMailOperation *self;
673 SendNewMailHelper *helper;
675 helper = (SendNewMailHelper *) user_data;
676 self = helper->mail_op;
677 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
683 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
684 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
685 "Error adding a msg to the send queue\n");
686 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
688 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
693 modest_mail_operation_notify_end (self);
695 g_object_unref (helper->mail_op);
696 g_slice_free (SendNewMailHelper, helper);
700 run_queue_start (TnySendQueue *self,
703 RunQueueHelper *helper = (RunQueueHelper *) user_data;
704 ModestMailOperation *mail_op;
706 g_debug ("%s sending queue successfully started", __FUNCTION__);
708 /* Wait for the message to be sent */
709 mail_op = modest_mail_operation_new (NULL);
710 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
712 modest_mail_operation_run_queue (mail_op, helper->queue);
713 g_object_unref (mail_op);
715 /* Free the helper and end operation */
716 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
720 run_queue_error_happened (TnySendQueue *queue,
726 RunQueueHelper *helper = (RunQueueHelper *) user_data;
727 ModestMailOperationPrivate *priv;
729 /* If we are here this means that the send queue could not
730 start to send emails. Shouldn't happen as this means that
731 we could not create the thread */
732 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
734 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
735 priv->error = g_error_copy ((const GError *) error);
737 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
738 /* This code is here for safety reasons. It should
739 never be called, because that would mean that we
740 are not controlling some error case */
741 g_warning ("%s Error %s should not happen",
742 __FUNCTION__, error->message);
745 /* Free helper and end operation */
746 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
750 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
756 ModestMailOperationPrivate *priv;
757 ModestMailOperation *self;
758 SendNewMailHelper *helper;
760 helper = (SendNewMailHelper *) user_data;
761 self = helper->mail_op;
762 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
768 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
769 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
770 "Error adding a msg to the send queue\n");
771 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
773 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
777 if (helper->notify) {
778 TnyTransportAccount *trans_account;
779 ModestTnySendQueue *queue;
781 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
783 queue = modest_runtime_get_send_queue (trans_account, TRUE);
785 RunQueueHelper *helper;
787 /* Create the helper */
788 helper = g_slice_new0 (RunQueueHelper);
789 helper->queue = g_object_ref (queue);
790 helper->self = g_object_ref (self);
792 /* if sending is ongoing wait for the queue to
793 stop. Otherwise wait for the queue-start
794 signal. It could happen that the queue
795 could not start, then check also the error
797 if (modest_tny_send_queue_sending_in_progress (queue)) {
798 run_queue_start (TNY_SEND_QUEUE (queue), helper);
800 helper->start_handler = g_signal_connect (queue, "queue-start",
801 G_CALLBACK (run_queue_start),
803 helper->error_handler = g_signal_connect (queue, "error-happened",
804 G_CALLBACK (run_queue_error_happened),
808 /* Finalize this mail operation */
809 modest_mail_operation_notify_end (self);
811 g_object_unref (trans_account);
813 g_warning ("No transport account for the operation");
817 g_object_unref (helper->mail_op);
818 g_slice_free (SendNewMailHelper, helper);
822 idle_create_msg_cb (gpointer idle_data)
824 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
826 /* This is a GDK lock because we are an idle callback and
827 * info->callback can contain Gtk+ code */
829 gdk_threads_enter (); /* CHECKED */
830 info->callback (info->mail_op, info->msg, info->userdata);
832 g_object_unref (info->mail_op);
834 g_object_unref (info->msg);
835 g_slice_free (CreateMsgIdleInfo, info);
836 gdk_threads_leave (); /* CHECKED */
842 create_msg_thread (gpointer thread_data)
844 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
845 TnyMsg *new_msg = NULL;
846 ModestMailOperationPrivate *priv;
849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
850 if (info->html_body == NULL) {
851 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
852 info->bcc, info->subject,
853 info->references, info->in_reply_to,
855 info->attachments_list, &attached,
858 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
859 info->bcc, info->subject,
860 info->references, info->in_reply_to,
862 info->plain_body, info->attachments_list,
863 info->images_list, &attached,
868 TnyHeader *header = tny_msg_get_header (new_msg);
870 /* Set priority flags in message */
871 if (info->priority_flags != TNY_HEADER_FLAG_NORMAL_PRIORITY)
872 tny_header_set_flag (header, info->priority_flags);
874 /* Set attachment flags in message */
875 if (info->attachments_list != NULL && attached > 0)
876 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
878 g_object_unref (G_OBJECT(header));
880 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
882 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
883 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
884 "modest: failed to create a new msg\n");
892 g_free (info->plain_body);
893 g_free (info->html_body);
894 g_free (info->subject);
895 g_free (info->references);
896 g_free (info->in_reply_to);
897 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
898 g_list_free (info->attachments_list);
899 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
900 g_list_free (info->images_list);
902 if (info->callback) {
903 CreateMsgIdleInfo *idle_info;
904 idle_info = g_slice_new0 (CreateMsgIdleInfo);
905 idle_info->mail_op = g_object_ref (info->mail_op);
906 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
907 idle_info->callback = info->callback;
908 idle_info->userdata = info->userdata;
909 g_idle_add (idle_create_msg_cb, idle_info);
911 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
914 g_object_unref (info->mail_op);
915 g_slice_free (CreateMsgInfo, info);
916 if (new_msg) g_object_unref(new_msg);
922 modest_mail_operation_create_msg (ModestMailOperation *self,
923 const gchar *from, const gchar *to,
924 const gchar *cc, const gchar *bcc,
925 const gchar *subject, const gchar *plain_body,
926 const gchar *html_body,
927 const GList *attachments_list,
928 const GList *images_list,
929 TnyHeaderFlags priority_flags,
930 const gchar *references,
931 const gchar *in_reply_to,
932 ModestMailOperationCreateMsgCallback callback,
935 CreateMsgInfo *info = NULL;
937 info = g_slice_new0 (CreateMsgInfo);
938 info->mail_op = g_object_ref (self);
940 info->from = g_strdup (from);
941 info->to = g_strdup (to);
942 info->cc = g_strdup (cc);
943 info->bcc = g_strdup (bcc);
944 info->subject = g_strdup (subject);
945 info->plain_body = g_strdup (plain_body);
946 info->html_body = g_strdup (html_body);
947 info->references = g_strdup (references);
948 info->in_reply_to = g_strdup (in_reply_to);
949 info->attachments_list = g_list_copy ((GList *) attachments_list);
950 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
951 info->images_list = g_list_copy ((GList *) images_list);
952 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
953 info->priority_flags = 0 | priority_flags;
955 info->callback = callback;
956 info->userdata = userdata;
958 g_thread_create (create_msg_thread, info, FALSE, NULL);
963 TnyTransportAccount *transport_account;
968 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
972 TnySendQueue *send_queue = NULL;
973 ModestMailOperationPrivate *priv = NULL;
974 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
975 TnyFolder *draft_folder = NULL;
976 TnyFolder *outbox_folder = NULL;
977 TnyHeader *header = NULL;
979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
982 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
983 modest_mail_operation_notify_end (self);
987 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
988 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
989 modest_mail_operation_notify_end (self);
993 /* Add message to send queue */
994 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
995 if (!TNY_IS_SEND_QUEUE(send_queue)) {
997 g_error_free (priv->error);
1000 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1001 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1002 "modest: could not find send queue for account\n");
1003 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1004 modest_mail_operation_notify_end (self);
1007 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
1008 helper->mail_op = g_object_ref (self);
1009 helper->notify = (info->draft_msg == NULL);
1011 /* Add the msg to the queue. The callback will free
1013 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1015 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1019 if (info->draft_msg != NULL) {
1020 TnyList *tmp_headers = NULL;
1021 TnyFolder *folder = NULL;
1022 TnyFolder *src_folder = NULL;
1023 TnyFolderType folder_type;
1024 TnyTransportAccount *transport_account = NULL;
1025 SendNewMailHelper *helper = NULL;
1027 /* To remove the old mail from its source folder, we need to get the
1028 * transport account of the original draft message (the transport account
1029 * might have been changed by the user) */
1030 header = tny_msg_get_header (info->draft_msg);
1031 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1032 modest_runtime_get_account_store(), header);
1033 if (transport_account == NULL)
1034 transport_account = g_object_ref(info->transport_account);
1035 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1036 TNY_FOLDER_TYPE_DRAFTS);
1037 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1038 TNY_FOLDER_TYPE_OUTBOX);
1039 g_object_unref(transport_account);
1041 if (!draft_folder) {
1042 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1044 modest_mail_operation_notify_end (self);
1047 if (!outbox_folder) {
1048 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1050 modest_mail_operation_notify_end (self);
1054 folder = tny_msg_get_folder (info->draft_msg);
1055 if (folder == NULL) {
1056 modest_mail_operation_notify_end (self);
1059 folder_type = modest_tny_folder_guess_folder_type (folder);
1061 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1062 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1064 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1065 src_folder = outbox_folder;
1067 src_folder = draft_folder;
1069 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1070 * because this function requires it to have a UID. */
1071 helper = g_slice_new (SendNewMailHelper);
1072 helper->mail_op = g_object_ref (self);
1073 helper->notify = TRUE;
1075 tmp_headers = tny_simple_list_new ();
1076 tny_list_append (tmp_headers, (GObject*) header);
1077 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1078 g_object_unref (tmp_headers);
1079 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1081 g_object_unref (folder);
1086 g_object_unref (header);
1087 if (info->draft_msg)
1088 g_object_unref (info->draft_msg);
1090 g_object_unref (draft_folder);
1092 g_object_unref (outbox_folder);
1093 if (info->transport_account)
1094 g_object_unref (info->transport_account);
1095 g_slice_free (SendNewMailInfo, info);
1099 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1100 TnyTransportAccount *transport_account,
1102 const gchar *from, const gchar *to,
1103 const gchar *cc, const gchar *bcc,
1104 const gchar *subject, const gchar *plain_body,
1105 const gchar *html_body,
1106 const GList *attachments_list,
1107 const GList *images_list,
1108 const gchar *references,
1109 const gchar *in_reply_to,
1110 TnyHeaderFlags priority_flags)
1112 ModestMailOperationPrivate *priv = NULL;
1113 SendNewMailInfo *info;
1115 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1116 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1119 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1120 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1121 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1123 modest_mail_operation_notify_start (self);
1125 /* Check parametters */
1127 /* Set status failed and set an error */
1128 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1129 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1130 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1131 _("Error trying to send a mail. You need to set at least one recipient"));
1132 modest_mail_operation_notify_end (self);
1135 info = g_slice_new0 (SendNewMailInfo);
1136 info->transport_account = transport_account;
1137 if (transport_account)
1138 g_object_ref (transport_account);
1139 info->draft_msg = draft_msg;
1141 g_object_ref (draft_msg);
1144 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1145 attachments_list, images_list, priority_flags,
1146 references, in_reply_to,
1147 modest_mail_operation_send_new_mail_cb, info);
1153 ModestMailOperation *mailop;
1155 SaveToDraftstCallback callback;
1157 } FinishSaveRemoteDraftInfo;
1160 finish_save_remote_draft (ModestAccountProtocol *protocol,
1162 const gchar *account_id,
1163 TnyMsg *new_remote_msg,
1168 FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
1169 ModestMailOperationPrivate *priv = NULL;
1171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1173 if (!priv->error && err != NULL) {
1174 /* Priority for errors in save to local stage */
1175 priv->error = g_error_copy (err);
1176 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1180 info->callback (info->mailop, info->msg, info->userdata);
1183 g_object_unref (info->msg);
1185 modest_mail_operation_notify_end (info->mailop);
1186 g_object_unref (info->mailop);
1188 g_slice_free (FinishSaveRemoteDraftInfo, info);
1193 TnyTransportAccount *transport_account;
1195 SaveToDraftstCallback callback;
1199 ModestMailOperation *mailop;
1200 } SaveToDraftsAddMsgInfo;
1203 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1208 ModestMailOperationPrivate *priv = NULL;
1209 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1210 GError *io_error = NULL;
1211 gboolean callback_called = FALSE;
1213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1215 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1216 io_error = priv->error;
1220 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1221 g_error_free(priv->error);
1224 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1226 if ((!priv->error) && (info->draft_msg != NULL)) {
1227 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1228 TnyFolder *src_folder = tny_header_get_folder (header);
1230 g_debug ("--- REMOVE AND SYNC");
1231 /* Remove the old draft */
1232 tny_folder_remove_msg (src_folder, header, NULL);
1234 /* Synchronize to expunge and to update the msg counts */
1235 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1236 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1237 g_debug ("--- REMOVED - SYNCED");
1239 g_object_unref (G_OBJECT(header));
1240 g_object_unref (G_OBJECT(src_folder));
1244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1246 g_error_free (io_error);
1249 } else if (io_error) {
1250 priv->error = io_error;
1251 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1253 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1256 if (info->transport_account) {
1257 ModestProtocolType transport_protocol_type;
1258 ModestProtocol *transport_protocol;
1260 transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
1262 transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1263 transport_protocol_type);
1264 if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
1265 FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
1266 srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
1267 srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
1268 srd_info->callback = info->callback;
1269 srd_info->userdata = info->user_data;
1270 modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol),
1271 tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
1272 info->msg, info->draft_msg,
1273 finish_save_remote_draft,
1276 callback_called = TRUE;
1280 /* Call the user callback */
1281 if (!callback_called && info->callback)
1282 info->callback (info->mailop, info->msg, info->user_data);
1284 if (info->transport_account)
1285 g_object_unref (G_OBJECT(info->transport_account));
1286 if (info->draft_msg)
1287 g_object_unref (G_OBJECT (info->draft_msg));
1289 g_object_unref (G_OBJECT(info->drafts));
1291 g_object_unref (G_OBJECT (info->msg));
1293 if (!callback_called)
1294 modest_mail_operation_notify_end (info->mailop);
1296 g_object_unref(info->mailop);
1297 g_slice_free (SaveToDraftsAddMsgInfo, info);
1302 TnyTransportAccount *transport_account;
1304 SaveToDraftstCallback callback;
1309 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1313 TnyFolder *drafts = NULL;
1314 ModestMailOperationPrivate *priv = NULL;
1315 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1320 if (!(priv->error)) {
1321 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1322 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1323 "modest: failed to create a new msg\n");
1326 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1327 TNY_FOLDER_TYPE_DRAFTS);
1328 if (!drafts && !(priv->error)) {
1329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1330 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1331 "modest: failed to create a new msg\n");
1335 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1337 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1338 cb_info->transport_account = g_object_ref(info->transport_account);
1339 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1340 cb_info->callback = info->callback;
1341 cb_info->user_data = info->user_data;
1342 cb_info->drafts = g_object_ref(drafts);
1343 cb_info->msg = g_object_ref(msg);
1344 cb_info->mailop = g_object_ref(self);
1345 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1349 /* Call the user callback */
1350 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1352 info->callback (self, msg, info->user_data);
1353 modest_mail_operation_notify_end (self);
1357 g_object_unref (G_OBJECT(drafts));
1358 if (info->draft_msg)
1359 g_object_unref (G_OBJECT (info->draft_msg));
1360 if (info->transport_account)
1361 g_object_unref (G_OBJECT(info->transport_account));
1362 g_slice_free (SaveToDraftsInfo, info);
1366 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1367 TnyTransportAccount *transport_account,
1369 const gchar *from, const gchar *to,
1370 const gchar *cc, const gchar *bcc,
1371 const gchar *subject, const gchar *plain_body,
1372 const gchar *html_body,
1373 const GList *attachments_list,
1374 const GList *images_list,
1375 TnyHeaderFlags priority_flags,
1376 const gchar *references,
1377 const gchar *in_reply_to,
1378 SaveToDraftstCallback callback,
1381 ModestMailOperationPrivate *priv = NULL;
1382 SaveToDraftsInfo *info = NULL;
1384 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1385 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1389 /* Get account and set it into mail_operation */
1390 priv->account = g_object_ref (transport_account);
1391 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1393 info = g_slice_new0 (SaveToDraftsInfo);
1394 info->transport_account = g_object_ref (transport_account);
1395 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1396 info->callback = callback;
1397 info->user_data = user_data;
1399 g_debug ("--- CREATE MESSAGE");
1400 modest_mail_operation_notify_start (self);
1401 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1402 attachments_list, images_list, priority_flags,
1403 references, in_reply_to,
1404 modest_mail_operation_save_to_drafts_cb, info);
1409 ModestMailOperation *mail_op;
1410 TnyMimePart *mime_part;
1412 GetMimePartSizeCallback callback;
1414 } GetMimePartSizeInfo;
1416 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1417 /* We use this folder observer to track the headers that have been
1418 * added to a folder */
1421 TnyList *new_headers;
1422 } InternalFolderObserver;
1425 GObjectClass parent;
1426 } InternalFolderObserverClass;
1428 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1430 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1431 internal_folder_observer,
1433 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1437 foreach_add_item (gpointer header, gpointer user_data)
1439 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1442 /* This is the method that looks for new messages in a folder */
1444 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1446 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1448 TnyFolderChangeChanged changed;
1450 changed = tny_folder_change_get_changed (change);
1452 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1455 /* Get added headers */
1456 list = tny_simple_list_new ();
1457 tny_folder_change_get_added_headers (change, list);
1459 /* Add them to the folder observer */
1460 tny_list_foreach (list, foreach_add_item,
1461 derived->new_headers);
1463 g_object_unref (G_OBJECT (list));
1468 internal_folder_observer_init (InternalFolderObserver *self)
1470 self->new_headers = tny_simple_list_new ();
1473 internal_folder_observer_finalize (GObject *object)
1475 InternalFolderObserver *self;
1477 self = (InternalFolderObserver *) object;
1478 g_object_unref (self->new_headers);
1480 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1483 tny_folder_observer_init (TnyFolderObserverIface *iface)
1485 iface->update = internal_folder_observer_update;
1488 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1490 GObjectClass *object_class;
1492 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1493 object_class = (GObjectClass*) klass;
1494 object_class->finalize = internal_folder_observer_finalize;
1498 destroy_update_account_info (UpdateAccountInfo *info)
1500 g_free (info->account_name);
1501 g_object_unref (info->folders);
1502 g_object_unref (info->mail_op);
1503 g_slice_free (UpdateAccountInfo, info);
1508 update_account_send_mail (UpdateAccountInfo *info)
1510 TnyTransportAccount *transport_account = NULL;
1511 ModestTnyAccountStore *account_store;
1513 if (info->update_folder_counts)
1516 account_store = modest_runtime_get_account_store ();
1518 /* We don't try to send messages while sending mails is blocked */
1519 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1522 /* Get the transport account */
1523 transport_account = (TnyTransportAccount *)
1524 modest_tny_account_store_get_server_account (account_store, info->account_name,
1525 TNY_ACCOUNT_TYPE_TRANSPORT);
1527 if (transport_account) {
1528 ModestTnySendQueue *send_queue;
1532 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1533 g_object_unref (transport_account);
1535 if (TNY_IS_SEND_QUEUE (send_queue)) {
1536 /* Get outbox folder */
1537 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1538 if (outbox) { /* this could fail in some cases */
1539 num_messages = tny_folder_get_all_count (outbox);
1540 g_object_unref (outbox);
1542 g_warning ("%s: could not get outbox", __FUNCTION__);
1546 if (num_messages != 0) {
1547 ModestMailOperation *mail_op;
1548 /* Reenable suspended items */
1549 mail_op = modest_mail_operation_new (NULL);
1550 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1552 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1555 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1563 update_account_get_msg_async_cb (TnyFolder *folder,
1569 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1570 ModestMailOperationPrivate *priv;
1572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1575 if (TNY_IS_MSG (msg)) {
1576 TnyHeader *header = tny_msg_get_header (msg);
1579 ModestMailOperationState *state;
1580 state = modest_mail_operation_clone_state (msg_info->mail_op);
1581 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1582 state->bytes_done = msg_info->sum_total_bytes;
1583 state->bytes_total = msg_info->total_bytes;
1585 /* Notify the status change. Only notify about changes
1586 referred to bytes */
1587 g_signal_emit (G_OBJECT (msg_info->mail_op),
1588 signals[PROGRESS_CHANGED_SIGNAL],
1591 g_object_unref (header);
1592 g_slice_free (ModestMailOperationState, state);
1596 if (priv->done == priv->total) {
1597 TnyList *new_headers;
1598 UpdateAccountInfo *info;
1600 /* After getting all the messages send the ones in the
1602 info = (UpdateAccountInfo *) msg_info->user_data;
1603 update_account_send_mail (info);
1605 /* Check if the operation was a success */
1607 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1609 /* Call the user callback and free */
1610 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1611 update_account_notify_user_and_free (info, new_headers);
1613 /* Delete the helper */
1615 g_object_unref (msg_info->msg);
1616 g_object_unref (msg_info->more_msgs);
1617 g_object_unref (msg_info->mail_op);
1618 g_slice_free (GetMsgInfo, msg_info);
1623 update_account_notify_user_and_free (UpdateAccountInfo *info,
1624 TnyList *new_headers)
1626 /* Set the account back to not busy */
1627 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1628 info->account_name, FALSE);
1632 info->callback (info->mail_op, new_headers, info->user_data);
1634 /* Mail operation end */
1635 modest_mail_operation_notify_end (info->mail_op);
1639 g_object_unref (new_headers);
1640 destroy_update_account_info (info);
1644 inbox_refreshed_cb (TnyFolder *inbox,
1649 UpdateAccountInfo *info;
1650 ModestMailOperationPrivate *priv;
1651 TnyIterator *new_headers_iter;
1652 GPtrArray *new_headers_array = NULL;
1653 gint max_size = G_MAXINT, retrieve_limit, i;
1654 ModestAccountMgr *mgr;
1655 ModestAccountRetrieveType retrieve_type;
1656 TnyList *new_headers = NULL;
1657 gboolean headers_only;
1658 time_t time_to_store;
1660 info = (UpdateAccountInfo *) user_data;
1661 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1662 mgr = modest_runtime_get_account_mgr ();
1664 if (canceled || err) {
1665 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1667 priv->error = g_error_copy (err);
1669 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1670 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1674 tny_folder_remove_observer (inbox, info->inbox_observer);
1675 g_object_unref (info->inbox_observer);
1676 info->inbox_observer = NULL;
1678 /* Notify the user about the error and then exit */
1679 update_account_notify_user_and_free (info, NULL);
1684 /* Try to send anyway */
1688 if (!info->update_folder_counts) {
1689 /* Set the last updated as the current time */
1690 #ifdef MODEST_USE_LIBTIME
1692 time_get_utc (&utc_tm);
1693 time_to_store = time_mktime (&utc_tm, "GMT");
1695 time_to_store = time (NULL);
1697 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
1699 /* Get the message max size */
1700 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1701 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1703 max_size = G_MAXINT;
1705 max_size = max_size * KB;
1708 /* Create the new headers array. We need it to sort the
1709 new headers by date */
1710 new_headers_array = g_ptr_array_new ();
1711 if (info->inbox_observer) {
1712 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1713 if (!tny_iterator_is_done (new_headers_iter)) {
1714 modest_platform_emit_folder_updated_signal (info->account_name, tny_folder_get_id (TNY_FOLDER (inbox)));
1716 while (!tny_iterator_is_done (new_headers_iter)) {
1717 TnyHeader *header = NULL;
1719 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1720 /* Apply per-message size limits */
1721 if (tny_header_get_message_size (header) < max_size)
1722 g_ptr_array_add (new_headers_array, g_object_ref (header));
1724 g_object_unref (header);
1725 tny_iterator_next (new_headers_iter);
1727 g_object_unref (new_headers_iter);
1729 tny_folder_remove_observer (inbox, info->inbox_observer);
1730 g_object_unref (info->inbox_observer);
1731 info->inbox_observer = NULL;
1734 if (new_headers_array->len == 0) {
1735 g_ptr_array_free (new_headers_array, FALSE);
1739 /* Get per-account message amount retrieval limit */
1740 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1741 if (retrieve_limit == 0)
1742 retrieve_limit = G_MAXINT;
1744 /* Get per-account retrieval type */
1745 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1746 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1749 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1751 /* Copy the headers to a list and free the array */
1752 new_headers = tny_simple_list_new ();
1753 for (i=0; i < new_headers_array->len; i++) {
1754 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1755 /* We want the first element to be the most recent
1756 one, that's why we reverse the list */
1757 tny_list_prepend (new_headers, G_OBJECT (header));
1759 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1760 g_ptr_array_free (new_headers_array, FALSE);
1762 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1765 GetMsgInfo *msg_info;
1768 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1770 iter = tny_list_create_iterator (new_headers);
1772 /* Create the message info */
1773 msg_info = g_slice_new0 (GetMsgInfo);
1774 msg_info->mail_op = g_object_ref (info->mail_op);
1775 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1776 msg_info->more_msgs = g_object_ref (iter);
1777 msg_info->msg = NULL;
1778 msg_info->user_data = info;
1780 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1781 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1782 TnyFolder *folder = tny_header_get_folder (header);
1784 /* Get message in an async way */
1785 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1788 g_object_unref (folder);
1789 g_object_unref (header);
1792 tny_iterator_next (iter);
1794 g_object_unref (iter);
1795 g_object_unref (new_headers);
1797 /* The mail operation will finish when the last
1798 message is retrieved */
1802 /* If we don't have to retrieve the new messages then
1804 update_account_send_mail (info);
1806 /* Check if the operation was a success */
1808 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1810 /* Call the user callback and free */
1811 update_account_notify_user_and_free (info, new_headers);
1815 inbox_refresh_status_update (GObject *obj,
1819 UpdateAccountInfo *info = NULL;
1820 ModestMailOperation *self = NULL;
1821 ModestMailOperationPrivate *priv = NULL;
1822 ModestMailOperationState *state;
1824 g_return_if_fail (user_data != NULL);
1825 g_return_if_fail (status != NULL);
1827 /* Show only the status information we want */
1828 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1831 info = (UpdateAccountInfo *) user_data;
1832 self = info->mail_op;
1833 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1835 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1837 priv->done = status->position;
1838 priv->total = status->of_total;
1840 state = modest_mail_operation_clone_state (self);
1842 /* This is not a GDK lock because we are a Tinymail callback and
1843 * Tinymail already acquires the Gdk lock */
1844 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1846 g_slice_free (ModestMailOperationState, state);
1850 recurse_folders_async_cb (TnyFolderStore *folder_store,
1856 UpdateAccountInfo *info;
1857 ModestMailOperationPrivate *priv;
1859 info = (UpdateAccountInfo *) user_data;
1860 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1862 if (err || canceled) {
1863 /* If the error was previosly set by another callback
1864 don't set it again */
1866 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1868 priv->error = g_error_copy (err);
1870 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1871 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1875 /* We're not getting INBOX children if we don't want to poke all */
1876 TnyIterator *iter = tny_list_create_iterator (list);
1877 while (!tny_iterator_is_done (iter)) {
1878 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1880 /* Add to the list of all folders */
1881 tny_list_append (info->folders, (GObject *) folder);
1883 if (info->poke_all) {
1884 TnyList *folders = tny_simple_list_new ();
1885 /* Add pending call */
1886 info->pending_calls++;
1888 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1889 recurse_folders_async_cb,
1891 g_object_unref (folders);
1894 g_object_unref (G_OBJECT (folder));
1896 tny_iterator_next (iter);
1898 g_object_unref (G_OBJECT (iter));
1901 /* Remove my own pending call */
1902 info->pending_calls--;
1904 /* This means that we have all the folders */
1905 if (info->pending_calls == 0) {
1906 TnyIterator *iter_all_folders;
1907 TnyFolder *inbox = NULL;
1909 /* If there was any error do not continue */
1911 update_account_notify_user_and_free (info, NULL);
1915 iter_all_folders = tny_list_create_iterator (info->folders);
1917 /* Do a poke status over all folders */
1918 while (!tny_iterator_is_done (iter_all_folders) &&
1919 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1920 TnyFolder *folder = NULL;
1922 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1924 if (!info->update_folder_counts && tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1925 /* Get a reference to the INBOX */
1926 inbox = g_object_ref (folder);
1928 /* Issue a poke status over the folder */
1930 tny_folder_poke_status (folder);
1933 /* Free and go to next */
1934 g_object_unref (folder);
1935 tny_iterator_next (iter_all_folders);
1937 g_object_unref (iter_all_folders);
1939 /* Refresh the INBOX */
1941 /* Refresh the folder. Our observer receives
1942 * the new emails during folder refreshes, so
1943 * we can use observer->new_headers
1945 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1946 tny_folder_add_observer (inbox, info->inbox_observer);
1948 /* Refresh the INBOX */
1949 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1950 g_object_unref (inbox);
1952 /* We could not perform the inbox refresh but
1953 we'll try to send mails anyway */
1954 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1960 modest_mail_operation_update_account (ModestMailOperation *self,
1961 const gchar *account_name,
1963 gboolean interactive,
1964 UpdateAccountCallback callback,
1967 UpdateAccountInfo *info = NULL;
1968 ModestMailOperationPrivate *priv = NULL;
1969 ModestTnyAccountStore *account_store = NULL;
1971 ModestMailOperationState *state;
1973 /* Init mail operation */
1974 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1977 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1978 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1980 /* Get the store account */
1981 account_store = modest_runtime_get_account_store ();
1983 modest_tny_account_store_get_server_account (account_store,
1985 TNY_ACCOUNT_TYPE_STORE);
1987 /* The above function could return NULL */
1988 if (!priv->account) {
1989 /* Check if the operation was a success */
1990 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1991 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1993 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1995 /* Call the user callback */
1997 callback (self, NULL, user_data);
1999 /* Notify about operation end */
2000 modest_mail_operation_notify_end (self);
2005 /* We have once seen priv->account getting finalized during this code,
2006 * therefore adding a reference (bug #82296) */
2008 g_object_ref (priv->account);
2010 /* Create the helper object */
2011 info = g_slice_new0 (UpdateAccountInfo);
2012 info->pending_calls = 1;
2013 info->folders = tny_simple_list_new ();
2014 info->mail_op = g_object_ref (self);
2015 info->poke_all = poke_all;
2016 info->interactive = interactive;
2017 info->update_folder_counts = FALSE;
2018 info->account_name = g_strdup (account_name);
2019 info->callback = callback;
2020 info->user_data = user_data;
2022 /* Set account busy */
2023 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2024 modest_mail_operation_notify_start (self);
2026 /* notify about the start of the operation */
2027 state = modest_mail_operation_clone_state (self);
2031 /* Start notifying progress */
2032 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2033 g_slice_free (ModestMailOperationState, state);
2035 /* Get all folders and continue in the callback */
2036 folders = tny_simple_list_new ();
2037 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2038 folders, NULL, TRUE,
2039 recurse_folders_async_cb,
2041 g_object_unref (folders);
2043 g_object_unref (priv->account);
2048 modest_mail_operation_update_folder_counts (ModestMailOperation *self,
2049 const gchar *account_name)
2051 UpdateAccountInfo *info = NULL;
2052 ModestMailOperationPrivate *priv = NULL;
2053 ModestTnyAccountStore *account_store = NULL;
2055 ModestMailOperationState *state;
2057 /* Init mail operation */
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2061 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2062 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UPDATE_FOLDER_COUNTS;
2064 /* Get the store account */
2065 account_store = modest_runtime_get_account_store ();
2067 modest_tny_account_store_get_server_account (account_store,
2069 TNY_ACCOUNT_TYPE_STORE);
2071 /* The above function could return NULL */
2072 if (!priv->account) {
2073 /* Check if the operation was a success */
2074 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2075 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2077 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2079 /* Notify about operation end */
2080 modest_mail_operation_notify_end (self);
2085 /* We have once seen priv->account getting finalized during this code,
2086 * therefore adding a reference (bug #82296) */
2088 g_object_ref (priv->account);
2090 /* Create the helper object */
2091 info = g_slice_new0 (UpdateAccountInfo);
2092 info->pending_calls = 1;
2093 info->folders = tny_simple_list_new ();
2094 info->mail_op = g_object_ref (self);
2095 info->poke_all = TRUE;
2096 info->interactive = FALSE;
2097 info->update_folder_counts = TRUE;
2098 info->account_name = g_strdup (account_name);
2099 info->callback = NULL;
2100 info->user_data = NULL;
2102 /* Set account busy */
2103 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2104 modest_mail_operation_notify_start (self);
2106 /* notify about the start of the operation */
2107 state = modest_mail_operation_clone_state (self);
2111 /* Start notifying progress */
2112 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2113 g_slice_free (ModestMailOperationState, state);
2115 /* Get all folders and continue in the callback */
2116 folders = tny_simple_list_new ();
2117 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2118 folders, NULL, TRUE,
2119 recurse_folders_async_cb,
2121 g_object_unref (folders);
2123 g_object_unref (priv->account);
2128 * Used to notify the queue from the main
2129 * loop. We call it inside an idle call to achieve that
2132 idle_notify_queue (gpointer data)
2134 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2136 gdk_threads_enter ();
2137 modest_mail_operation_notify_end (mail_op);
2138 gdk_threads_leave ();
2139 g_object_unref (mail_op);
2145 compare_headers_by_date (gconstpointer a,
2148 TnyHeader **header1, **header2;
2149 time_t sent1, sent2;
2151 header1 = (TnyHeader **) a;
2152 header2 = (TnyHeader **) b;
2154 sent1 = tny_header_get_date_sent (*header1);
2155 sent2 = tny_header_get_date_sent (*header2);
2157 /* We want the most recent ones (greater time_t) at the
2166 /* ******************************************************************* */
2167 /* ************************** STORE ACTIONS ************************* */
2168 /* ******************************************************************* */
2171 ModestMailOperation *mail_op;
2172 CreateFolderUserCallback callback;
2178 create_folder_cb (TnyFolderStore *parent_folder,
2180 TnyFolder *new_folder,
2184 ModestMailOperationPrivate *priv;
2185 CreateFolderInfo *info;
2187 info = (CreateFolderInfo *) user_data;
2188 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2190 if (canceled || err) {
2191 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2193 priv->error = g_error_copy (err);
2195 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2196 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2199 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2202 /* The user will unref the new_folder */
2204 info->callback (info->mail_op, parent_folder,
2205 new_folder, info->user_data);
2207 /* Notify about operation end */
2208 modest_mail_operation_notify_end (info->mail_op);
2211 g_object_unref (info->mail_op);
2212 g_slice_free (CreateFolderInfo, info);
2216 modest_mail_operation_create_folder (ModestMailOperation *self,
2217 TnyFolderStore *parent,
2219 CreateFolderUserCallback callback,
2222 ModestMailOperationPrivate *priv;
2224 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2225 g_return_if_fail (name);
2227 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2228 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2229 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2230 g_object_ref (parent) :
2231 modest_tny_folder_get_account (TNY_FOLDER (parent));
2233 /* Check for already existing folder */
2234 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2235 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2236 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2237 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2238 _CS("ckdg_ib_folder_already_exists"));
2242 if (TNY_IS_FOLDER (parent)) {
2243 /* Check folder rules */
2244 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2245 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2246 /* Set status failed and set an error */
2247 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2248 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2249 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2250 _("mail_in_ui_folder_create_error"));
2254 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2255 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2256 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2257 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2258 _("mail_in_ui_folder_create_error"));
2262 CreateFolderInfo *info;
2264 info = g_slice_new0 (CreateFolderInfo);
2265 info->mail_op = g_object_ref (self);
2266 info->callback = callback;
2267 info->user_data = user_data;
2269 modest_mail_operation_notify_start (self);
2271 /* Create the folder */
2272 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2275 /* Call the user callback anyway */
2277 callback (self, parent, NULL, user_data);
2278 /* Notify about operation end */
2279 modest_mail_operation_notify_end (self);
2284 modest_mail_operation_remove_folder (ModestMailOperation *self,
2286 gboolean remove_to_trash)
2288 ModestMailOperationPrivate *priv;
2289 ModestTnyFolderRules rules;
2291 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2292 g_return_if_fail (TNY_IS_FOLDER (folder));
2294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2296 /* Check folder rules */
2297 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2298 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2299 /* Set status failed and set an error */
2300 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2301 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2302 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2303 _("mail_in_ui_folder_delete_error"));
2307 /* Get the account */
2308 priv->account = modest_tny_folder_get_account (folder);
2309 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2311 /* Delete folder or move to trash */
2312 if (remove_to_trash) {
2313 TnyFolder *trash_folder = NULL;
2314 trash_folder = modest_tny_account_get_special_folder (priv->account,
2315 TNY_FOLDER_TYPE_TRASH);
2316 /* TODO: error_handling */
2318 modest_mail_operation_notify_start (self);
2319 modest_mail_operation_xfer_folder (self, folder,
2320 TNY_FOLDER_STORE (trash_folder),
2322 g_object_unref (trash_folder);
2324 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2327 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2329 modest_mail_operation_notify_start (self);
2330 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2331 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2334 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2336 g_object_unref (parent);
2338 g_warning ("%s: could not get parent folder", __FUNCTION__);
2342 /* Notify about operation end */
2343 modest_mail_operation_notify_end (self);
2347 transfer_folder_status_cb (GObject *obj,
2351 ModestMailOperation *self;
2352 ModestMailOperationPrivate *priv;
2353 ModestMailOperationState *state;
2354 XFerFolderAsyncHelper *helper;
2356 g_return_if_fail (status != NULL);
2358 /* Show only the status information we want */
2359 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2362 helper = (XFerFolderAsyncHelper *) user_data;
2363 g_return_if_fail (helper != NULL);
2365 self = helper->mail_op;
2366 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2368 priv->done = status->position;
2369 priv->total = status->of_total;
2371 state = modest_mail_operation_clone_state (self);
2373 /* This is not a GDK lock because we are a Tinymail callback
2374 * which is already GDK locked by Tinymail */
2376 /* no gdk_threads_enter (), CHECKED */
2378 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2380 /* no gdk_threads_leave (), CHECKED */
2382 g_slice_free (ModestMailOperationState, state);
2386 transfer_folder_cb (TnyFolder *folder,
2388 TnyFolderStore *into,
2389 TnyFolder *new_folder,
2393 XFerFolderAsyncHelper *helper;
2394 ModestMailOperation *self = NULL;
2395 ModestMailOperationPrivate *priv = NULL;
2397 helper = (XFerFolderAsyncHelper *) user_data;
2398 g_return_if_fail (helper != NULL);
2400 self = helper->mail_op;
2401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2404 priv->error = g_error_copy (err);
2406 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2407 } else if (cancelled) {
2408 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2409 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2410 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2411 _("Transference of %s was cancelled."),
2412 tny_folder_get_name (folder));
2415 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2418 /* Update state of new folder */
2420 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2421 tny_folder_poke_status (new_folder);
2424 /* Notify about operation end */
2425 modest_mail_operation_notify_end (self);
2427 /* If user defined callback function was defined, call it */
2428 if (helper->user_callback) {
2430 /* This is not a GDK lock because we are a Tinymail callback
2431 * which is already GDK locked by Tinymail */
2433 /* no gdk_threads_enter (), CHECKED */
2434 helper->user_callback (self, new_folder, helper->user_data);
2435 /* no gdk_threads_leave () , CHECKED */
2439 g_object_unref (helper->mail_op);
2440 g_slice_free (XFerFolderAsyncHelper, helper);
2445 * This function checks if the new name is a valid name for our local
2446 * folders account. The new name could not be the same than then name
2447 * of any of the mandatory local folders
2449 * We can not rely on tinymail because tinymail does not check the
2450 * name of the virtual folders that the account could have in the case
2451 * that we're doing a rename (because it directly calls Camel which
2452 * knows nothing about our virtual folders).
2454 * In the case of an actual copy/move (i.e. move/copy a folder between
2455 * accounts) tinymail uses the tny_folder_store_create_account which
2456 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2457 * checks the new name of the folder, so this call in that case
2458 * wouldn't be needed. *But* NOTE that if tinymail changes its
2459 * implementation (if folder transfers within the same account is no
2460 * longer implemented as a rename) this call will allow Modest to work
2463 * If the new name is not valid, this function will set the status to
2464 * failed and will set also an error in the mail operation
2467 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2468 TnyFolderStore *into,
2469 const gchar *new_name)
2471 if (TNY_IS_ACCOUNT (into) &&
2472 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2473 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2475 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2476 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2477 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2478 _CS("ckdg_ib_folder_already_exists"));
2485 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2487 TnyFolderStore *parent,
2488 gboolean delete_original,
2489 XferFolderAsyncUserCallback user_callback,
2492 ModestMailOperationPrivate *priv = NULL;
2493 ModestTnyFolderRules parent_rules = 0, rules;
2494 XFerFolderAsyncHelper *helper = NULL;
2495 const gchar *folder_name = NULL;
2496 const gchar *error_msg;
2498 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2499 g_return_if_fail (TNY_IS_FOLDER (folder));
2500 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2503 folder_name = tny_folder_get_name (folder);
2505 /* Set the error msg */
2506 error_msg = _("mail_in_ui_folder_move_target_error");
2508 /* Get account and set it into mail_operation */
2509 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2510 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2511 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2513 /* Get folder rules */
2514 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2515 if (TNY_IS_FOLDER (parent))
2516 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2518 /* Apply operation constraints */
2519 if ((gpointer) parent == (gpointer) folder ||
2520 (!TNY_IS_FOLDER_STORE (parent)) ||
2521 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2524 } else if (TNY_IS_FOLDER (parent) &&
2525 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2529 } else if (TNY_IS_FOLDER (parent) &&
2530 TNY_IS_FOLDER_STORE (folder) &&
2531 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2532 TNY_FOLDER_STORE (folder))) {
2533 /* Do not move a parent into a child */
2535 } else if (TNY_IS_FOLDER_STORE (parent) &&
2536 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2537 /* Check that the new folder name is not used by any
2540 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2541 /* Check that the new folder name is not used by any
2542 special local folder */
2545 /* Create the helper */
2546 helper = g_slice_new0 (XFerFolderAsyncHelper);
2547 helper->mail_op = g_object_ref (self);
2548 helper->user_callback = user_callback;
2549 helper->user_data = user_data;
2551 /* Move/Copy folder */
2552 modest_mail_operation_notify_start (self);
2553 tny_folder_copy_async (folder,
2555 tny_folder_get_name (folder),
2558 transfer_folder_status_cb,
2564 /* Set status failed and set an error */
2565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2567 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2570 /* Call the user callback if exists */
2572 user_callback (self, NULL, user_data);
2574 /* Notify the queue */
2575 modest_mail_operation_notify_end (self);
2579 modest_mail_operation_rename_folder (ModestMailOperation *self,
2582 XferFolderAsyncUserCallback user_callback,
2585 ModestMailOperationPrivate *priv;
2586 ModestTnyFolderRules rules;
2587 XFerFolderAsyncHelper *helper;
2589 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2590 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2591 g_return_if_fail (name);
2593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2595 /* Get account and set it into mail_operation */
2596 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2597 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2599 /* Check folder rules */
2600 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2601 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2603 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2606 TnyFolderStore *into;
2608 into = tny_folder_get_folder_store (folder);
2610 /* Check that the new folder name is not used by any
2611 special local folder */
2612 if (new_name_valid_if_local_account (priv, into, name)) {
2613 /* Create the helper */
2614 helper = g_slice_new0 (XFerFolderAsyncHelper);
2615 helper->mail_op = g_object_ref(self);
2616 helper->user_callback = user_callback;
2617 helper->user_data = user_data;
2619 /* Rename. Camel handles folder subscription/unsubscription */
2620 modest_mail_operation_notify_start (self);
2621 tny_folder_copy_async (folder, into, name, TRUE,
2623 transfer_folder_status_cb,
2625 g_object_unref (into);
2627 g_object_unref (into);
2634 /* Set status failed and set an error */
2635 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2636 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2637 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2638 _("FIXME: unable to rename"));
2641 user_callback (self, NULL, user_data);
2643 /* Notify about operation end */
2644 modest_mail_operation_notify_end (self);
2647 /* ******************************************************************* */
2648 /* ************************** MSG ACTIONS ************************* */
2649 /* ******************************************************************* */
2652 modest_mail_operation_find_msg (ModestMailOperation *self,
2654 const gchar *msg_uid,
2655 gboolean progress_feedback,
2656 GetMsgAsyncUserCallback user_callback,
2659 GetMsgInfo *helper = NULL;
2660 ModestMailOperationPrivate *priv;
2662 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2663 g_return_if_fail (msg_uid != NULL);
2665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2666 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2670 /* Check memory low */
2671 if (_check_memory_low (self)) {
2673 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2674 modest_mail_operation_notify_end (self);
2678 /* Get account and set it into mail_operation */
2679 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2681 /* Check for cached messages */
2682 if (progress_feedback) {
2683 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2685 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2688 /* Create the helper */
2689 helper = g_slice_new0 (GetMsgInfo);
2690 helper->header = NULL;
2691 helper->mail_op = g_object_ref (self);
2692 helper->user_callback = user_callback;
2693 helper->user_data = user_data;
2694 helper->destroy_notify = NULL;
2695 helper->last_total_bytes = 0;
2696 helper->sum_total_bytes = 0;
2697 helper->total_bytes = 0;
2698 helper->more_msgs = NULL;
2699 helper->get_parts = NULL;
2702 modest_mail_operation_notify_start (self);
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],
2711 g_slice_free (ModestMailOperationState, state);
2713 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2717 modest_mail_operation_get_msg (ModestMailOperation *self,
2719 gboolean progress_feedback,
2720 GetMsgAsyncUserCallback user_callback,
2723 GetMsgInfo *helper = NULL;
2725 ModestMailOperationPrivate *priv;
2727 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2728 g_return_if_fail (TNY_IS_HEADER (header));
2730 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2731 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2735 /* Check memory low */
2736 if (_check_memory_low (self)) {
2738 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2739 modest_mail_operation_notify_end (self);
2743 /* Get account and set it into mail_operation */
2744 folder = tny_header_get_folder (header);
2745 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2747 /* Check for cached messages */
2748 if (progress_feedback) {
2749 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2750 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2752 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2754 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2757 /* Create the helper */
2758 helper = g_slice_new0 (GetMsgInfo);
2759 helper->header = g_object_ref (header);
2760 helper->mail_op = g_object_ref (self);
2761 helper->user_callback = user_callback;
2762 helper->user_data = user_data;
2763 helper->destroy_notify = NULL;
2764 helper->last_total_bytes = 0;
2765 helper->sum_total_bytes = 0;
2766 helper->total_bytes = tny_header_get_message_size (header);
2767 helper->more_msgs = NULL;
2768 helper->get_parts = NULL;
2771 modest_mail_operation_notify_start (self);
2773 /* notify about the start of the operation */
2774 ModestMailOperationState *state;
2775 state = modest_mail_operation_clone_state (self);
2778 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2780 g_slice_free (ModestMailOperationState, state);
2782 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2784 g_object_unref (G_OBJECT (folder));
2788 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2791 gboolean progress_feedback,
2792 GetMsgAsyncUserCallback user_callback,
2795 GetMsgInfo *helper = NULL;
2797 ModestMailOperationPrivate *priv;
2799 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2800 g_return_if_fail (TNY_IS_HEADER (header));
2802 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2803 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2807 /* Check memory low */
2808 if (_check_memory_low (self)) {
2810 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2811 modest_mail_operation_notify_end (self);
2815 /* Get account and set it into mail_operation */
2816 folder = tny_header_get_folder (header);
2817 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2818 const gchar *acc_name;
2819 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2820 priv->account = modest_tny_account_store_get_server_account
2821 (modest_runtime_get_account_store (),
2823 TNY_ACCOUNT_TYPE_STORE);
2824 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2825 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2827 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2830 /* Check for cached messages */
2831 if (progress_feedback) {
2832 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2833 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2835 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2837 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2840 /* Create the helper */
2841 helper = g_slice_new0 (GetMsgInfo);
2842 helper->header = g_object_ref (header);
2843 helper->mail_op = g_object_ref (self);
2844 helper->user_callback = user_callback;
2845 helper->user_data = user_data;
2846 helper->destroy_notify = NULL;
2847 helper->last_total_bytes = 0;
2848 helper->sum_total_bytes = 0;
2849 helper->total_bytes = tny_header_get_message_size (header);
2850 helper->more_msgs = NULL;
2851 helper->get_parts = tny_list_create_iterator (parts);
2854 modest_mail_operation_notify_start (self);
2856 /* notify about the start of the operation */
2857 ModestMailOperationState *state;
2858 state = modest_mail_operation_clone_state (self);
2861 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2863 g_slice_free (ModestMailOperationState, state);
2865 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2867 g_object_unref (G_OBJECT (folder));
2871 get_msg_status_cb (GObject *obj,
2875 GetMsgInfo *helper = NULL;
2877 g_return_if_fail (status != NULL);
2879 /* Show only the status information we want */
2880 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2883 helper = (GetMsgInfo *) user_data;
2884 g_return_if_fail (helper != NULL);
2886 /* Notify progress */
2887 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2888 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2892 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2895 TnyFolder *folder = NULL;
2897 helper = (GetMsgInfo *) user_data;
2899 if (helper->header) {
2900 folder = tny_header_get_folder (helper->header);
2903 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2905 if (folder) g_object_unref (folder);
2909 get_msg_async_cb (TnyFolder *folder,
2915 GetMsgInfo *info = NULL;
2916 ModestMailOperationPrivate *priv = NULL;
2919 info = (GetMsgInfo *) user_data;
2921 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2924 if (info->more_msgs) {
2925 tny_iterator_next (info->more_msgs);
2926 finished = (tny_iterator_is_done (info->more_msgs));
2927 } else if (info->get_parts) {
2928 tny_iterator_next (info->get_parts);
2929 finished = (tny_iterator_is_done (info->get_parts));
2931 finished = (priv->done == priv->total) ? TRUE : FALSE;
2934 /* If canceled by the user, ignore the error given by Tinymail */
2938 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2940 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2941 priv->error = g_error_copy ((const GError *) err);
2943 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2945 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2946 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2947 "%s", err->message);
2949 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2950 /* Set the success status before calling the user callback */
2951 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2954 if (info->header == NULL && msg)
2955 info->header = tny_msg_get_header (msg);
2957 /* Call the user callback */
2958 if (info->user_callback && (finished || (info->get_parts == NULL)))
2959 info->user_callback (info->mail_op, info->header, canceled,
2960 msg, err, info->user_data);
2962 /* Notify about operation end if this is the last callback */
2964 /* Free user data */
2965 if (info->destroy_notify)
2966 info->destroy_notify (info->user_data);
2968 /* Notify about operation end */
2969 modest_mail_operation_notify_end (info->mail_op);
2973 g_object_unref (info->msg);
2974 if (info->more_msgs)
2975 g_object_unref (info->more_msgs);
2977 g_object_unref (info->header);
2978 g_object_unref (info->mail_op);
2979 g_slice_free (GetMsgInfo, info);
2980 } else if (info->get_parts) {
2981 CamelStream *null_stream;
2982 TnyStream *tny_null_stream;
2985 if (info->msg == NULL && msg != NULL)
2986 info->msg = g_object_ref (msg);
2988 null_stream = camel_stream_null_new ();
2989 tny_null_stream = tny_camel_stream_new (null_stream);
2991 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
2992 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
2993 get_msg_async_get_part_cb,
2996 g_object_unref (tny_null_stream);
2997 g_object_unref (part);
2999 } else if (info->more_msgs) {
3000 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
3001 TnyFolder *folder = tny_header_get_folder (header);
3003 g_object_unref (info->header);
3004 info->header = g_object_ref (header);
3006 /* Retrieve the next message */
3007 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
3009 g_object_unref (header);
3010 g_object_unref (folder);
3012 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
3017 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
3018 TnyList *header_list,
3019 GetMsgAsyncUserCallback user_callback,
3021 GDestroyNotify notify)
3023 ModestMailOperationPrivate *priv = NULL;
3025 TnyIterator *iter = NULL;
3026 gboolean has_uncached_messages;
3028 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3030 /* Init mail operation */
3031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3032 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3034 priv->total = tny_list_get_length(header_list);
3036 /* Check memory low */
3037 if (_check_memory_low (self)) {
3038 if (user_callback) {
3039 TnyHeader *header = NULL;
3042 if (tny_list_get_length (header_list) > 0) {
3043 iter = tny_list_create_iterator (header_list);
3044 header = (TnyHeader *) tny_iterator_get_current (iter);
3045 g_object_unref (iter);
3047 user_callback (self, header, FALSE, NULL, priv->error, user_data);
3049 g_object_unref (header);
3053 /* Notify about operation end */
3054 modest_mail_operation_notify_end (self);
3058 /* Check uncached messages */
3059 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
3060 !has_uncached_messages && !tny_iterator_is_done (iter);
3061 tny_iterator_next (iter)) {
3064 header = (TnyHeader *) tny_iterator_get_current (iter);
3065 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
3066 has_uncached_messages = TRUE;
3067 g_object_unref (header);
3069 g_object_unref (iter);
3070 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
3072 /* Get account and set it into mail_operation */
3073 if (tny_list_get_length (header_list) >= 1) {
3074 TnyIterator *iterator = tny_list_create_iterator (header_list);
3075 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
3077 TnyFolder *folder = tny_header_get_folder (header);
3079 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3080 g_object_unref (folder);
3082 g_object_unref (header);
3084 g_object_unref (iterator);
3087 msg_list_size = compute_message_list_size (header_list, 0);
3089 modest_mail_operation_notify_start (self);
3090 iter = tny_list_create_iterator (header_list);
3091 if (!tny_iterator_is_done (iter)) {
3092 /* notify about the start of the operation */
3093 ModestMailOperationState *state;
3094 state = modest_mail_operation_clone_state (self);
3097 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3100 GetMsgInfo *msg_info = NULL;
3101 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3102 TnyFolder *folder = tny_header_get_folder (header);
3104 /* Create the message info */
3105 msg_info = g_slice_new0 (GetMsgInfo);
3106 msg_info->mail_op = g_object_ref (self);
3107 msg_info->header = g_object_ref (header);
3108 msg_info->more_msgs = g_object_ref (iter);
3109 msg_info->user_callback = user_callback;
3110 msg_info->user_data = user_data;
3111 msg_info->destroy_notify = notify;
3112 msg_info->last_total_bytes = 0;
3113 msg_info->sum_total_bytes = 0;
3114 msg_info->total_bytes = msg_list_size;
3115 msg_info->msg = NULL;
3117 /* The callback will call it per each header */
3118 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3120 /* Free and go on */
3121 g_object_unref (header);
3122 g_object_unref (folder);
3123 g_slice_free (ModestMailOperationState, state);
3125 g_object_unref (iter);
3130 remove_msgs_async_cb (TnyFolder *folder,
3136 const gchar *account_name;
3137 TnyAccount *account;
3138 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3139 ModestMailOperation *self;
3140 ModestMailOperationPrivate *priv;
3141 ModestProtocolRegistry *protocol_registry;
3142 SyncFolderHelper *helper;
3144 self = (ModestMailOperation *) user_data;
3145 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3146 protocol_registry = modest_runtime_get_protocol_registry ();
3148 if (canceled || err) {
3149 /* If canceled by the user, ignore the error given by Tinymail */
3151 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3153 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3154 priv->error = g_error_copy ((const GError *) err);
3155 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3158 modest_mail_operation_notify_end (self);
3159 g_object_unref (self);
3163 account = modest_tny_folder_get_account (folder);
3164 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3165 account_proto = modest_tny_account_get_protocol_type (account);
3166 g_object_unref (account);
3168 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3169 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3179 helper = g_slice_new0 (SyncFolderHelper);
3180 helper->mail_op = g_object_ref (self);
3181 helper->user_callback = NULL;
3182 helper->user_data = NULL;
3185 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3187 /* Remove the extra reference */
3188 g_object_unref (self);
3192 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3194 gboolean remove_to_trash /*ignored*/)
3196 TnyFolder *folder = NULL;
3197 ModestMailOperationPrivate *priv;
3198 TnyIterator *iter = NULL;
3199 TnyHeader *header = NULL;
3200 TnyList *remove_headers = NULL;
3201 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3202 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3204 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3205 g_return_if_fail (TNY_IS_LIST (headers));
3207 if (remove_to_trash)
3208 g_warning ("remove to trash is not implemented");
3210 if (tny_list_get_length(headers) == 0) {
3211 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3212 goto cleanup; /* nothing to do */
3215 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3217 /* Get folder from first header and sync it */
3218 iter = tny_list_create_iterator (headers);
3219 header = TNY_HEADER (tny_iterator_get_current (iter));
3220 g_object_unref (iter);
3222 folder = tny_header_get_folder (header);
3223 if (!TNY_IS_FOLDER(folder)) {
3224 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3228 /* Use the merged folder if we're removing messages from outbox */
3229 if (modest_tny_folder_is_local_folder (folder)) {
3230 ModestTnyLocalFoldersAccount *local_account;
3232 local_account = (ModestTnyLocalFoldersAccount *)
3233 modest_tny_account_store_get_local_folders_account (accstore);
3234 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3235 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3236 g_object_unref (folder);
3237 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3239 g_object_unref (local_account);
3242 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3243 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3245 while (!tny_iterator_is_done (headers_iter)) {
3246 TnyTransportAccount *traccount = NULL;
3247 TnyHeader *hdr = NULL;
3249 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3250 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3253 ModestTnySendQueueStatus status;
3254 ModestTnySendQueue *send_queue;
3256 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3257 if (TNY_IS_SEND_QUEUE (send_queue)) {
3260 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3261 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3262 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3263 if (G_UNLIKELY (remove_headers == NULL))
3264 remove_headers = tny_simple_list_new ();
3265 tny_list_append(remove_headers, G_OBJECT(hdr));
3269 g_object_unref(traccount);
3271 g_object_unref(hdr);
3272 tny_iterator_next (headers_iter);
3274 g_object_unref(headers_iter);
3277 /* Get account and set it into mail_operation */
3278 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3279 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3280 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3282 if (!remove_headers)
3283 remove_headers = g_object_ref (headers);
3285 /* remove message from folder */
3286 modest_mail_operation_notify_start (self);
3287 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3288 NULL, g_object_ref (self));
3292 g_object_unref (remove_headers);
3294 g_object_unref (header);
3296 g_object_unref (folder);
3300 notify_progress_of_multiple_messages (ModestMailOperation *self,
3302 gint *last_total_bytes,
3303 gint *sum_total_bytes,
3305 gboolean increment_done)
3307 ModestMailOperationPrivate *priv;
3308 ModestMailOperationState *state;
3309 gboolean is_num_bytes = FALSE;
3311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3313 /* We know that tinymail sends us information about
3314 * transferred bytes with this particular message
3316 if (status->message)
3317 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3319 state = modest_mail_operation_clone_state (self);
3320 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3321 /* We know that we're in a different message when the
3322 total number of bytes to transfer is different. Of
3323 course it could fail if we're transferring messages
3324 of the same size, but this is a workarround */
3325 if (status->of_total != *last_total_bytes) {
3326 /* We need to increment the done when there is
3327 no information about each individual
3328 message, we need to do this in message
3329 transfers, and we don't do it for getting
3333 *sum_total_bytes += *last_total_bytes;
3334 *last_total_bytes = status->of_total;
3336 state->bytes_done += status->position + *sum_total_bytes;
3337 state->bytes_total = total_bytes;
3339 /* Notify the status change. Only notify about changes
3340 referred to bytes */
3341 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3345 g_slice_free (ModestMailOperationState, state);
3349 transfer_msgs_status_cb (GObject *obj,
3353 XFerMsgsAsyncHelper *helper;
3355 g_return_if_fail (status != NULL);
3357 /* Show only the status information we want */
3358 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3361 helper = (XFerMsgsAsyncHelper *) user_data;
3362 g_return_if_fail (helper != NULL);
3364 /* Notify progress */
3365 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3366 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3370 transfer_msgs_sync_folder_cb (TnyFolder *self,
3375 XFerMsgsAsyncHelper *helper;
3376 /* We don't care here about the results of the
3378 helper = (XFerMsgsAsyncHelper *) user_data;
3380 /* Notify about operation end */
3381 modest_mail_operation_notify_end (helper->mail_op);
3383 /* If user defined callback function was defined, call it */
3384 if (helper->user_callback)
3385 helper->user_callback (helper->mail_op, helper->user_data);
3388 if (helper->more_msgs)
3389 g_object_unref (helper->more_msgs);
3390 if (helper->headers)
3391 g_object_unref (helper->headers);
3392 if (helper->dest_folder)
3393 g_object_unref (helper->dest_folder);
3394 if (helper->mail_op)
3395 g_object_unref (helper->mail_op);
3396 g_slice_free (XFerMsgsAsyncHelper, helper);
3400 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3402 XFerMsgsAsyncHelper *helper;
3403 ModestMailOperation *self;
3404 ModestMailOperationPrivate *priv;
3405 gboolean finished = TRUE;
3407 helper = (XFerMsgsAsyncHelper *) user_data;
3408 self = helper->mail_op;
3410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3413 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3415 priv->error = g_error_copy (err);
3417 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3418 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3419 if (helper->more_msgs) {
3420 /* We'll transfer the next message in the list */
3421 tny_iterator_next (helper->more_msgs);
3422 if (!tny_iterator_is_done (helper->more_msgs)) {
3423 GObject *next_header;
3424 g_object_unref (helper->headers);
3425 helper->headers = tny_simple_list_new ();
3426 next_header = tny_iterator_get_current (helper->more_msgs);
3427 tny_list_append (helper->headers, next_header);
3428 g_object_unref (next_header);
3434 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3439 /* Synchronize the source folder contents. This should
3440 be done by tinymail but the camel_folder_sync it's
3441 actually disabled in transfer_msgs_thread_clean
3442 because it's supposed to cause hangs */
3443 tny_folder_sync_async (folder, helper->delete,
3444 transfer_msgs_sync_folder_cb,
3447 /* Transfer more messages */
3448 tny_folder_transfer_msgs_async (folder,
3450 helper->dest_folder,
3453 transfer_msgs_status_cb,
3458 /* Computes the size of the messages the headers in the list belongs
3459 to. If num_elements is different from 0 then it only takes into
3460 account the first num_elements for the calculation */
3462 compute_message_list_size (TnyList *headers,
3466 guint size = 0, element = 0;
3468 /* If num_elements is not valid then take all into account */
3469 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3470 num_elements = tny_list_get_length (headers);
3472 iter = tny_list_create_iterator (headers);
3473 while (!tny_iterator_is_done (iter) && element < num_elements) {
3474 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3475 size += tny_header_get_message_size (header);
3476 g_object_unref (header);
3477 tny_iterator_next (iter);
3480 g_object_unref (iter);
3486 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3489 gboolean delete_original,
3490 XferMsgsAsyncUserCallback user_callback,
3493 ModestMailOperationPrivate *priv = NULL;
3494 TnyIterator *iter = NULL;
3495 TnyFolder *src_folder = NULL;
3496 XFerMsgsAsyncHelper *helper = NULL;
3497 TnyHeader *header = NULL;
3498 ModestTnyFolderRules rules = 0;
3499 TnyAccount *dst_account = NULL;
3500 gboolean leave_on_server;
3501 ModestMailOperationState *state;
3502 ModestProtocolRegistry *protocol_registry;
3503 ModestProtocolType account_protocol;
3505 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3506 g_return_if_fail (headers && TNY_IS_LIST (headers));
3507 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3509 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3510 protocol_registry = modest_runtime_get_protocol_registry ();
3512 priv->total = tny_list_get_length (headers);
3514 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3515 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3517 /* Apply folder rules */
3518 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3519 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3520 /* Set status failed and set an error */
3521 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3522 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3523 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3524 _CS("ckct_ib_unable_to_paste_here"));
3525 /* Notify the queue */
3526 modest_mail_operation_notify_end (self);
3530 /* Get source folder */
3531 iter = tny_list_create_iterator (headers);
3532 header = TNY_HEADER (tny_iterator_get_current (iter));
3534 src_folder = tny_header_get_folder (header);
3535 g_object_unref (header);
3537 g_object_unref (iter);
3539 if (src_folder == NULL) {
3540 /* Notify the queue */
3541 modest_mail_operation_notify_end (self);
3543 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3548 /* Check folder source and destination */
3549 if (src_folder == folder) {
3550 /* Set status failed and set an error */
3551 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3552 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3553 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3554 _("mail_in_ui_folder_copy_target_error"));
3556 /* Notify the queue */
3557 modest_mail_operation_notify_end (self);
3560 g_object_unref (src_folder);
3564 /* Create the helper */
3565 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3566 helper->mail_op = g_object_ref(self);
3567 helper->dest_folder = g_object_ref(folder);
3568 helper->user_callback = user_callback;
3569 helper->user_data = user_data;
3570 helper->last_total_bytes = 0;
3571 helper->sum_total_bytes = 0;
3572 helper->total_bytes = compute_message_list_size (headers, 0);
3574 /* Get account and set it into mail_operation */
3575 priv->account = modest_tny_folder_get_account (src_folder);
3576 dst_account = modest_tny_folder_get_account (folder);
3578 if (priv->account == dst_account) {
3579 /* Transfer all messages at once using the fast
3580 * method. Note that depending on the server this
3581 * might not be that fast, and might not be
3582 * user-cancellable either */
3583 helper->headers = g_object_ref (headers);
3584 helper->more_msgs = NULL;
3586 /* Transfer messages one by one so the user can cancel
3589 helper->headers = tny_simple_list_new ();
3590 helper->more_msgs = tny_list_create_iterator (headers);
3591 hdr = tny_iterator_get_current (helper->more_msgs);
3592 tny_list_append (helper->headers, hdr);
3593 g_object_unref (hdr);
3596 /* If leave_on_server is set to TRUE then don't use
3597 delete_original, we always pass FALSE. This is because
3598 otherwise tinymail will try to sync the source folder and
3599 this could cause an error if we're offline while
3600 transferring an already downloaded message from a POP
3602 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3603 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3604 const gchar *account_name;
3606 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3607 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3610 leave_on_server = FALSE;
3613 /* Do not delete messages if leave on server is TRUE */
3614 helper->delete = (leave_on_server) ? FALSE : delete_original;
3616 modest_mail_operation_notify_start (self);
3618 /* Start notifying progress */
3619 state = modest_mail_operation_clone_state (self);
3622 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3623 g_slice_free (ModestMailOperationState, state);
3625 tny_folder_transfer_msgs_async (src_folder,
3630 transfer_msgs_status_cb,
3632 g_object_unref (src_folder);
3633 g_object_unref (dst_account);
3638 on_refresh_folder (TnyFolder *folder,
3643 RefreshAsyncHelper *helper = NULL;
3644 ModestMailOperation *self = NULL;
3645 ModestMailOperationPrivate *priv = NULL;
3647 helper = (RefreshAsyncHelper *) user_data;
3648 self = helper->mail_op;
3649 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3651 g_return_if_fail(priv!=NULL);
3654 priv->error = g_error_copy (error);
3655 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3660 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3661 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3662 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3663 _("Error trying to refresh the contents of %s"),
3664 tny_folder_get_name (folder));
3668 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3671 /* Call user defined callback, if it exists */
3672 if (helper->user_callback) {
3674 /* This is not a GDK lock because we are a Tinymail callback and
3675 * Tinymail already acquires the Gdk lock */
3676 helper->user_callback (self, folder, helper->user_data);
3680 g_slice_free (RefreshAsyncHelper, helper);
3682 /* Notify about operation end */
3683 modest_mail_operation_notify_end (self);
3684 g_object_unref(self);
3688 on_refresh_folder_status_update (GObject *obj,
3692 RefreshAsyncHelper *helper = NULL;
3693 ModestMailOperation *self = NULL;
3694 ModestMailOperationPrivate *priv = NULL;
3695 ModestMailOperationState *state;
3697 g_return_if_fail (user_data != NULL);
3698 g_return_if_fail (status != NULL);
3700 /* Show only the status information we want */
3701 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3704 helper = (RefreshAsyncHelper *) user_data;
3705 self = helper->mail_op;
3706 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3708 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3710 priv->done = status->position;
3711 priv->total = status->of_total;
3713 state = modest_mail_operation_clone_state (self);
3715 /* This is not a GDK lock because we are a Tinymail callback and
3716 * Tinymail already acquires the Gdk lock */
3717 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3719 g_slice_free (ModestMailOperationState, state);
3723 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3725 RefreshAsyncUserCallback user_callback,
3728 ModestMailOperationPrivate *priv = NULL;
3729 RefreshAsyncHelper *helper = NULL;
3731 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3733 /* Check memory low */
3734 if (_check_memory_low (self)) {
3736 user_callback (self, folder, user_data);
3737 /* Notify about operation end */
3738 modest_mail_operation_notify_end (self);
3742 /* Get account and set it into mail_operation */
3743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3744 priv->account = modest_tny_folder_get_account (folder);
3745 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3747 /* Create the helper */
3748 helper = g_slice_new0 (RefreshAsyncHelper);
3749 helper->mail_op = g_object_ref(self);
3750 helper->user_callback = user_callback;
3751 helper->user_data = user_data;
3753 modest_mail_operation_notify_start (self);
3755 /* notify that the operation was started */
3756 ModestMailOperationState *state;
3757 state = modest_mail_operation_clone_state (self);
3760 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3762 g_slice_free (ModestMailOperationState, state);
3764 tny_folder_refresh_async (folder,
3766 on_refresh_folder_status_update,
3771 run_queue_notify_and_destroy (RunQueueHelper *helper,
3772 ModestMailOperationStatus status)
3774 ModestMailOperationPrivate *priv;
3777 if (helper->error_handler &&
3778 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3779 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3780 if (helper->start_handler &&
3781 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3782 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3783 if (helper->stop_handler &&
3784 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3785 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3789 priv->status = status;
3792 modest_mail_operation_notify_end (helper->self);
3795 g_object_unref (helper->queue);
3796 g_object_unref (helper->self);
3797 g_slice_free (RunQueueHelper, helper);
3801 run_queue_stop (ModestTnySendQueue *queue,
3804 RunQueueHelper *helper;
3806 g_debug ("%s sending queue stopped", __FUNCTION__);
3808 helper = (RunQueueHelper *) user_data;
3809 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3813 modest_mail_operation_run_queue (ModestMailOperation *self,
3814 ModestTnySendQueue *queue)
3816 ModestMailOperationPrivate *priv;
3817 RunQueueHelper *helper;
3819 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3820 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3821 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3823 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3824 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3825 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3827 /* Create the helper */
3828 helper = g_slice_new0 (RunQueueHelper);
3829 helper->queue = g_object_ref (queue);
3830 helper->self = g_object_ref (self);
3831 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3832 G_CALLBACK (run_queue_stop),
3835 /* Notify operation has started */
3836 modest_mail_operation_notify_start (self);
3837 g_debug ("%s, run queue started", __FUNCTION__);
3841 queue_wakeup_callback (ModestTnySendQueue *queue,
3846 ModestMailOperation *mail_op;
3847 ModestMailOperationPrivate *priv;
3849 mail_op = (ModestMailOperation *) userdata;
3850 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3852 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3853 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3856 modest_mail_operation_notify_end (mail_op);
3857 g_object_unref (mail_op);
3861 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3862 ModestTnySendQueue *queue)
3864 ModestMailOperationPrivate *priv;
3866 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3867 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3870 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3871 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3872 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3874 g_object_ref (self);
3876 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3877 modest_mail_operation_notify_start (self);
3881 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3883 ModestMailOperation *self = (ModestMailOperation *) userdata;
3884 ModestMailOperationPrivate *priv;
3886 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3887 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3888 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3890 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3892 modest_mail_operation_notify_end (self);
3893 g_object_unref (self);
3897 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3899 ModestMailOperationPrivate *priv;
3901 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3902 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3903 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3905 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3907 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3908 priv->account = NULL;
3909 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3911 modest_mail_operation_notify_start (self);
3912 g_object_ref (self);
3913 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3917 sync_folder_finish_callback (TnyFolder *self,
3923 ModestMailOperationPrivate *priv;
3924 SyncFolderHelper *helper;
3926 helper = (SyncFolderHelper *) user_data;
3927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3929 /* If canceled by the user, ignore the error given by Tinymail */
3931 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3933 /* If the operation was a sync then the status is
3934 failed, but if it's part of another operation then
3935 just set it as finished with errors */
3936 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3937 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3939 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3940 priv->error = g_error_copy ((const GError *) err);
3941 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3943 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3947 if (helper->user_callback)
3948 helper->user_callback (helper->mail_op, self, helper->user_data);
3950 modest_mail_operation_notify_end (helper->mail_op);
3953 g_object_unref (helper->mail_op);
3954 g_slice_free (SyncFolderHelper, helper);
3958 modest_mail_operation_sync_folder (ModestMailOperation *self,
3961 SyncFolderCallback callback,
3964 ModestMailOperationPrivate *priv;
3965 SyncFolderHelper *helper;
3967 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3968 g_return_if_fail (TNY_IS_FOLDER (folder));
3969 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3971 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3972 priv->account = modest_tny_folder_get_account (folder);
3973 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3976 helper = g_slice_new0 (SyncFolderHelper);
3977 helper->mail_op = g_object_ref (self);
3978 helper->user_callback = callback;
3979 helper->user_data = user_data;
3981 modest_mail_operation_notify_start (self);
3982 tny_folder_sync_async (folder, expunge,
3983 (TnyFolderCallback) sync_folder_finish_callback,
3988 modest_mail_operation_notify_start (ModestMailOperation *self)
3990 ModestMailOperationPrivate *priv = NULL;
3992 g_return_if_fail (self);
3994 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3996 /* Ensure that all the fields are filled correctly */
3997 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3999 /* Notify the observers about the mail operation. We do not
4000 wrapp this emission because we assume that this function is
4001 always called from within the main lock */
4002 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
4007 * It's used by the mail operation queue to notify the observers
4008 * attached to that signal that the operation finished. We need to use
4009 * that because tinymail does not give us the progress of a given
4010 * operation when it finishes (it directly calls the operation
4014 modest_mail_operation_notify_end (ModestMailOperation *self)
4016 ModestMailOperationPrivate *priv = NULL;
4018 g_return_if_fail (self);
4020 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4022 /* Notify the observers about the mail operation end. We do
4023 not wrapp this emission because we assume that this
4024 function is always called from within the main lock */
4025 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
4027 /* Remove the error user data */
4028 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
4029 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
4033 modest_mail_operation_get_account (ModestMailOperation *self)
4035 ModestMailOperationPrivate *priv = NULL;
4037 g_return_val_if_fail (self, NULL);
4039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4041 return (priv->account) ? g_object_ref (priv->account) : NULL;
4045 modest_mail_operation_noop (ModestMailOperation *self)
4047 ModestMailOperationPrivate *priv = NULL;
4049 g_return_if_fail (self);
4051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4052 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4053 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
4057 /* This mail operation does nothing actually */
4058 modest_mail_operation_notify_start (self);
4059 modest_mail_operation_notify_end (self);
4064 modest_mail_operation_to_string (ModestMailOperation *self)
4066 const gchar *type, *status, *account_id;
4067 ModestMailOperationPrivate *priv = NULL;
4069 g_return_val_if_fail (self, NULL);
4071 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4073 /* new operations don't have anything interesting */
4074 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
4075 return g_strdup_printf ("%p <new operation>", self);
4077 switch (priv->op_type) {
4078 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
4079 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
4080 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
4081 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
4082 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
4083 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
4084 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
4085 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
4086 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
4087 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
4088 default: type = "UNEXPECTED"; break;
4091 switch (priv->status) {
4092 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4093 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4094 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4095 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4096 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4097 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4098 default: status= "UNEXPECTED"; break;
4101 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4103 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4104 priv->done, priv->total,
4105 priv->error && priv->error->message ? priv->error->message : "");
4109 * Once the mail operations were objects this will be no longer
4110 * needed. I don't like it, but we need it for the moment
4113 _check_memory_low (ModestMailOperation *mail_op)
4115 if (modest_platform_check_memory_low (NULL, FALSE)) {
4116 ModestMailOperationPrivate *priv;
4118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4119 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4120 g_set_error (&(priv->error),
4121 MODEST_MAIL_OPERATION_ERROR,
4122 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4123 "Not enough memory to complete the operation");