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,
870 /* Set priority flags in message */
871 header = tny_msg_get_header (new_msg);
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 = 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, 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 while (!tny_iterator_is_done (new_headers_iter)) {
1714 TnyHeader *header = NULL;
1716 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1717 /* Apply per-message size limits */
1718 if (tny_header_get_message_size (header) < max_size)
1719 g_ptr_array_add (new_headers_array, g_object_ref (header));
1721 g_object_unref (header);
1722 tny_iterator_next (new_headers_iter);
1724 g_object_unref (new_headers_iter);
1726 tny_folder_remove_observer (inbox, info->inbox_observer);
1727 g_object_unref (info->inbox_observer);
1728 info->inbox_observer = NULL;
1731 if (new_headers_array->len == 0) {
1732 g_ptr_array_free (new_headers_array, FALSE);
1736 /* Get per-account message amount retrieval limit */
1737 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1738 if (retrieve_limit == 0)
1739 retrieve_limit = G_MAXINT;
1741 /* Get per-account retrieval type */
1742 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1743 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1746 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1748 /* Copy the headers to a list and free the array */
1749 new_headers = tny_simple_list_new ();
1750 for (i=0; i < new_headers_array->len; i++) {
1751 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1752 /* We want the first element to be the most recent
1753 one, that's why we reverse the list */
1754 tny_list_prepend (new_headers, G_OBJECT (header));
1756 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1757 g_ptr_array_free (new_headers_array, FALSE);
1759 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1762 GetMsgInfo *msg_info;
1765 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1767 iter = tny_list_create_iterator (new_headers);
1769 /* Create the message info */
1770 msg_info = g_slice_new0 (GetMsgInfo);
1771 msg_info->mail_op = g_object_ref (info->mail_op);
1772 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1773 msg_info->more_msgs = g_object_ref (iter);
1774 msg_info->msg = NULL;
1775 msg_info->user_data = info;
1777 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1778 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1779 TnyFolder *folder = tny_header_get_folder (header);
1781 /* Get message in an async way */
1782 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1785 g_object_unref (folder);
1786 g_object_unref (header);
1789 tny_iterator_next (iter);
1791 g_object_unref (iter);
1792 g_object_unref (new_headers);
1794 /* The mail operation will finish when the last
1795 message is retrieved */
1799 /* If we don't have to retrieve the new messages then
1801 update_account_send_mail (info);
1803 /* Check if the operation was a success */
1805 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1807 /* Call the user callback and free */
1808 update_account_notify_user_and_free (info, new_headers);
1812 inbox_refresh_status_update (GObject *obj,
1816 UpdateAccountInfo *info = NULL;
1817 ModestMailOperation *self = NULL;
1818 ModestMailOperationPrivate *priv = NULL;
1819 ModestMailOperationState *state;
1821 g_return_if_fail (user_data != NULL);
1822 g_return_if_fail (status != NULL);
1824 /* Show only the status information we want */
1825 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1828 info = (UpdateAccountInfo *) user_data;
1829 self = info->mail_op;
1830 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1832 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1834 priv->done = status->position;
1835 priv->total = status->of_total;
1837 state = modest_mail_operation_clone_state (self);
1839 /* This is not a GDK lock because we are a Tinymail callback and
1840 * Tinymail already acquires the Gdk lock */
1841 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1843 g_slice_free (ModestMailOperationState, state);
1847 recurse_folders_async_cb (TnyFolderStore *folder_store,
1853 UpdateAccountInfo *info;
1854 ModestMailOperationPrivate *priv;
1856 info = (UpdateAccountInfo *) user_data;
1857 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1859 if (err || canceled) {
1860 /* If the error was previosly set by another callback
1861 don't set it again */
1863 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1865 priv->error = g_error_copy (err);
1867 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1868 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1872 /* We're not getting INBOX children if we don't want to poke all */
1873 TnyIterator *iter = tny_list_create_iterator (list);
1874 while (!tny_iterator_is_done (iter)) {
1875 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1877 /* Add to the list of all folders */
1878 tny_list_append (info->folders, (GObject *) folder);
1880 if (info->poke_all) {
1881 TnyList *folders = tny_simple_list_new ();
1882 /* Add pending call */
1883 info->pending_calls++;
1885 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1886 recurse_folders_async_cb,
1888 g_object_unref (folders);
1891 g_object_unref (G_OBJECT (folder));
1893 tny_iterator_next (iter);
1895 g_object_unref (G_OBJECT (iter));
1898 /* Remove my own pending call */
1899 info->pending_calls--;
1901 /* This means that we have all the folders */
1902 if (info->pending_calls == 0) {
1903 TnyIterator *iter_all_folders;
1904 TnyFolder *inbox = NULL;
1906 /* If there was any error do not continue */
1908 update_account_notify_user_and_free (info, NULL);
1912 iter_all_folders = tny_list_create_iterator (info->folders);
1914 /* Do a poke status over all folders */
1915 while (!tny_iterator_is_done (iter_all_folders) &&
1916 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1917 TnyFolder *folder = NULL;
1919 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1921 if (!info->update_folder_counts && tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1922 /* Get a reference to the INBOX */
1923 inbox = g_object_ref (folder);
1925 /* Issue a poke status over the folder */
1927 tny_folder_poke_status (folder);
1930 /* Free and go to next */
1931 g_object_unref (folder);
1932 tny_iterator_next (iter_all_folders);
1934 g_object_unref (iter_all_folders);
1936 /* Refresh the INBOX */
1938 /* Refresh the folder. Our observer receives
1939 * the new emails during folder refreshes, so
1940 * we can use observer->new_headers
1942 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1943 tny_folder_add_observer (inbox, info->inbox_observer);
1945 /* Refresh the INBOX */
1946 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1947 g_object_unref (inbox);
1949 /* We could not perform the inbox refresh but
1950 we'll try to send mails anyway */
1951 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1957 modest_mail_operation_update_account (ModestMailOperation *self,
1958 const gchar *account_name,
1960 gboolean interactive,
1961 UpdateAccountCallback callback,
1964 UpdateAccountInfo *info = NULL;
1965 ModestMailOperationPrivate *priv = NULL;
1966 ModestTnyAccountStore *account_store = NULL;
1968 ModestMailOperationState *state;
1970 /* Init mail operation */
1971 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1974 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1975 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1977 /* Get the store account */
1978 account_store = modest_runtime_get_account_store ();
1980 modest_tny_account_store_get_server_account (account_store,
1982 TNY_ACCOUNT_TYPE_STORE);
1984 /* The above function could return NULL */
1985 if (!priv->account) {
1986 /* Check if the operation was a success */
1987 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1988 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1990 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1992 /* Call the user callback */
1994 callback (self, NULL, user_data);
1996 /* Notify about operation end */
1997 modest_mail_operation_notify_end (self);
2002 /* We have once seen priv->account getting finalized during this code,
2003 * therefore adding a reference (bug #82296) */
2005 g_object_ref (priv->account);
2007 /* Create the helper object */
2008 info = g_slice_new0 (UpdateAccountInfo);
2009 info->pending_calls = 1;
2010 info->folders = tny_simple_list_new ();
2011 info->mail_op = g_object_ref (self);
2012 info->poke_all = poke_all;
2013 info->interactive = interactive;
2014 info->update_folder_counts = FALSE;
2015 info->account_name = g_strdup (account_name);
2016 info->callback = callback;
2017 info->user_data = user_data;
2019 /* Set account busy */
2020 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2021 modest_mail_operation_notify_start (self);
2023 /* notify about the start of the operation */
2024 state = modest_mail_operation_clone_state (self);
2028 /* Start notifying progress */
2029 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2030 g_slice_free (ModestMailOperationState, state);
2032 /* Get all folders and continue in the callback */
2033 folders = tny_simple_list_new ();
2034 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2035 folders, NULL, TRUE,
2036 recurse_folders_async_cb,
2038 g_object_unref (folders);
2040 g_object_unref (priv->account);
2045 modest_mail_operation_update_folder_counts (ModestMailOperation *self,
2046 const gchar *account_name)
2048 UpdateAccountInfo *info = NULL;
2049 ModestMailOperationPrivate *priv = NULL;
2050 ModestTnyAccountStore *account_store = NULL;
2052 ModestMailOperationState *state;
2054 /* Init mail operation */
2055 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2058 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2059 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UPDATE_FOLDER_COUNTS;
2061 /* Get the store account */
2062 account_store = modest_runtime_get_account_store ();
2064 modest_tny_account_store_get_server_account (account_store,
2066 TNY_ACCOUNT_TYPE_STORE);
2068 /* The above function could return NULL */
2069 if (!priv->account) {
2070 /* Check if the operation was a success */
2071 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2072 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2074 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2076 /* Notify about operation end */
2077 modest_mail_operation_notify_end (self);
2082 /* We have once seen priv->account getting finalized during this code,
2083 * therefore adding a reference (bug #82296) */
2085 g_object_ref (priv->account);
2087 /* Create the helper object */
2088 info = g_slice_new0 (UpdateAccountInfo);
2089 info->pending_calls = 1;
2090 info->folders = tny_simple_list_new ();
2091 info->mail_op = g_object_ref (self);
2092 info->poke_all = TRUE;
2093 info->interactive = FALSE;
2094 info->update_folder_counts = TRUE;
2095 info->account_name = g_strdup (account_name);
2096 info->callback = NULL;
2097 info->user_data = NULL;
2099 /* Set account busy */
2100 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2101 modest_mail_operation_notify_start (self);
2103 /* notify about the start of the operation */
2104 state = modest_mail_operation_clone_state (self);
2108 /* Start notifying progress */
2109 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2110 g_slice_free (ModestMailOperationState, state);
2112 /* Get all folders and continue in the callback */
2113 folders = tny_simple_list_new ();
2114 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2115 folders, NULL, TRUE,
2116 recurse_folders_async_cb,
2118 g_object_unref (folders);
2120 g_object_unref (priv->account);
2125 * Used to notify the queue from the main
2126 * loop. We call it inside an idle call to achieve that
2129 idle_notify_queue (gpointer data)
2131 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2133 gdk_threads_enter ();
2134 modest_mail_operation_notify_end (mail_op);
2135 gdk_threads_leave ();
2136 g_object_unref (mail_op);
2142 compare_headers_by_date (gconstpointer a,
2145 TnyHeader **header1, **header2;
2146 time_t sent1, sent2;
2148 header1 = (TnyHeader **) a;
2149 header2 = (TnyHeader **) b;
2151 sent1 = tny_header_get_date_sent (*header1);
2152 sent2 = tny_header_get_date_sent (*header2);
2154 /* We want the most recent ones (greater time_t) at the
2163 /* ******************************************************************* */
2164 /* ************************** STORE ACTIONS ************************* */
2165 /* ******************************************************************* */
2168 ModestMailOperation *mail_op;
2169 CreateFolderUserCallback callback;
2175 create_folder_cb (TnyFolderStore *parent_folder,
2177 TnyFolder *new_folder,
2181 ModestMailOperationPrivate *priv;
2182 CreateFolderInfo *info;
2184 info = (CreateFolderInfo *) user_data;
2185 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2187 if (canceled || err) {
2188 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2190 priv->error = g_error_copy (err);
2192 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2193 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2196 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2199 /* The user will unref the new_folder */
2201 info->callback (info->mail_op, parent_folder,
2202 new_folder, info->user_data);
2204 /* Notify about operation end */
2205 modest_mail_operation_notify_end (info->mail_op);
2208 g_object_unref (info->mail_op);
2209 g_slice_free (CreateFolderInfo, info);
2213 modest_mail_operation_create_folder (ModestMailOperation *self,
2214 TnyFolderStore *parent,
2216 CreateFolderUserCallback callback,
2219 ModestMailOperationPrivate *priv;
2221 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2222 g_return_if_fail (name);
2224 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2225 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2226 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2227 g_object_ref (parent) :
2228 modest_tny_folder_get_account (TNY_FOLDER (parent));
2230 /* Check for already existing folder */
2231 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2232 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2233 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2234 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2235 _CS("ckdg_ib_folder_already_exists"));
2239 if (TNY_IS_FOLDER (parent)) {
2240 /* Check folder rules */
2241 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2242 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2243 /* Set status failed and set an error */
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2245 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2246 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2247 _("mail_in_ui_folder_create_error"));
2251 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2252 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2253 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2254 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2255 _("mail_in_ui_folder_create_error"));
2259 CreateFolderInfo *info;
2261 info = g_slice_new0 (CreateFolderInfo);
2262 info->mail_op = g_object_ref (self);
2263 info->callback = callback;
2264 info->user_data = user_data;
2266 modest_mail_operation_notify_start (self);
2268 /* Create the folder */
2269 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2272 /* Call the user callback anyway */
2274 callback (self, parent, NULL, user_data);
2275 /* Notify about operation end */
2276 modest_mail_operation_notify_end (self);
2281 modest_mail_operation_remove_folder (ModestMailOperation *self,
2283 gboolean remove_to_trash)
2285 ModestMailOperationPrivate *priv;
2286 ModestTnyFolderRules rules;
2288 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2289 g_return_if_fail (TNY_IS_FOLDER (folder));
2291 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2293 /* Check folder rules */
2294 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2295 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2296 /* Set status failed and set an error */
2297 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2298 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2299 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2300 _("mail_in_ui_folder_delete_error"));
2304 /* Get the account */
2305 priv->account = modest_tny_folder_get_account (folder);
2306 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2308 /* Delete folder or move to trash */
2309 if (remove_to_trash) {
2310 TnyFolder *trash_folder = NULL;
2311 trash_folder = modest_tny_account_get_special_folder (priv->account,
2312 TNY_FOLDER_TYPE_TRASH);
2313 /* TODO: error_handling */
2315 modest_mail_operation_notify_start (self);
2316 modest_mail_operation_xfer_folder (self, folder,
2317 TNY_FOLDER_STORE (trash_folder),
2319 g_object_unref (trash_folder);
2321 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2324 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2326 modest_mail_operation_notify_start (self);
2327 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2328 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2331 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2333 g_object_unref (parent);
2335 g_warning ("%s: could not get parent folder", __FUNCTION__);
2339 /* Notify about operation end */
2340 modest_mail_operation_notify_end (self);
2344 transfer_folder_status_cb (GObject *obj,
2348 ModestMailOperation *self;
2349 ModestMailOperationPrivate *priv;
2350 ModestMailOperationState *state;
2351 XFerFolderAsyncHelper *helper;
2353 g_return_if_fail (status != NULL);
2355 /* Show only the status information we want */
2356 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2359 helper = (XFerFolderAsyncHelper *) user_data;
2360 g_return_if_fail (helper != NULL);
2362 self = helper->mail_op;
2363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2365 priv->done = status->position;
2366 priv->total = status->of_total;
2368 state = modest_mail_operation_clone_state (self);
2370 /* This is not a GDK lock because we are a Tinymail callback
2371 * which is already GDK locked by Tinymail */
2373 /* no gdk_threads_enter (), CHECKED */
2375 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2377 /* no gdk_threads_leave (), CHECKED */
2379 g_slice_free (ModestMailOperationState, state);
2383 transfer_folder_cb (TnyFolder *folder,
2385 TnyFolderStore *into,
2386 TnyFolder *new_folder,
2390 XFerFolderAsyncHelper *helper;
2391 ModestMailOperation *self = NULL;
2392 ModestMailOperationPrivate *priv = NULL;
2394 helper = (XFerFolderAsyncHelper *) user_data;
2395 g_return_if_fail (helper != NULL);
2397 self = helper->mail_op;
2398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2401 priv->error = g_error_copy (err);
2403 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2404 } else if (cancelled) {
2405 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2406 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2407 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2408 _("Transference of %s was cancelled."),
2409 tny_folder_get_name (folder));
2412 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2415 /* Update state of new folder */
2417 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2418 tny_folder_poke_status (new_folder);
2421 /* Notify about operation end */
2422 modest_mail_operation_notify_end (self);
2424 /* If user defined callback function was defined, call it */
2425 if (helper->user_callback) {
2427 /* This is not a GDK lock because we are a Tinymail callback
2428 * which is already GDK locked by Tinymail */
2430 /* no gdk_threads_enter (), CHECKED */
2431 helper->user_callback (self, new_folder, helper->user_data);
2432 /* no gdk_threads_leave () , CHECKED */
2436 g_object_unref (helper->mail_op);
2437 g_slice_free (XFerFolderAsyncHelper, helper);
2442 * This function checks if the new name is a valid name for our local
2443 * folders account. The new name could not be the same than then name
2444 * of any of the mandatory local folders
2446 * We can not rely on tinymail because tinymail does not check the
2447 * name of the virtual folders that the account could have in the case
2448 * that we're doing a rename (because it directly calls Camel which
2449 * knows nothing about our virtual folders).
2451 * In the case of an actual copy/move (i.e. move/copy a folder between
2452 * accounts) tinymail uses the tny_folder_store_create_account which
2453 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2454 * checks the new name of the folder, so this call in that case
2455 * wouldn't be needed. *But* NOTE that if tinymail changes its
2456 * implementation (if folder transfers within the same account is no
2457 * longer implemented as a rename) this call will allow Modest to work
2460 * If the new name is not valid, this function will set the status to
2461 * failed and will set also an error in the mail operation
2464 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2465 TnyFolderStore *into,
2466 const gchar *new_name)
2468 if (TNY_IS_ACCOUNT (into) &&
2469 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2470 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2472 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2473 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2474 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2475 _CS("ckdg_ib_folder_already_exists"));
2482 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2484 TnyFolderStore *parent,
2485 gboolean delete_original,
2486 XferFolderAsyncUserCallback user_callback,
2489 ModestMailOperationPrivate *priv = NULL;
2490 ModestTnyFolderRules parent_rules = 0, rules;
2491 XFerFolderAsyncHelper *helper = NULL;
2492 const gchar *folder_name = NULL;
2493 const gchar *error_msg;
2495 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2496 g_return_if_fail (TNY_IS_FOLDER (folder));
2497 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2499 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2500 folder_name = tny_folder_get_name (folder);
2502 /* Set the error msg */
2503 error_msg = _("mail_in_ui_folder_move_target_error");
2505 /* Get account and set it into mail_operation */
2506 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2507 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2508 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2510 /* Get folder rules */
2511 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2512 if (TNY_IS_FOLDER (parent))
2513 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2515 /* Apply operation constraints */
2516 if ((gpointer) parent == (gpointer) folder ||
2517 (!TNY_IS_FOLDER_STORE (parent)) ||
2518 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2521 } else if (TNY_IS_FOLDER (parent) &&
2522 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2526 } else if (TNY_IS_FOLDER (parent) &&
2527 TNY_IS_FOLDER_STORE (folder) &&
2528 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2529 TNY_FOLDER_STORE (folder))) {
2530 /* Do not move a parent into a child */
2532 } else if (TNY_IS_FOLDER_STORE (parent) &&
2533 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2534 /* Check that the new folder name is not used by any
2537 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2538 /* Check that the new folder name is not used by any
2539 special local folder */
2542 /* Create the helper */
2543 helper = g_slice_new0 (XFerFolderAsyncHelper);
2544 helper->mail_op = g_object_ref (self);
2545 helper->user_callback = user_callback;
2546 helper->user_data = user_data;
2548 /* Move/Copy folder */
2549 modest_mail_operation_notify_start (self);
2550 tny_folder_copy_async (folder,
2552 tny_folder_get_name (folder),
2555 transfer_folder_status_cb,
2561 /* Set status failed and set an error */
2562 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2563 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2564 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2567 /* Call the user callback if exists */
2569 user_callback (self, NULL, user_data);
2571 /* Notify the queue */
2572 modest_mail_operation_notify_end (self);
2576 modest_mail_operation_rename_folder (ModestMailOperation *self,
2579 XferFolderAsyncUserCallback user_callback,
2582 ModestMailOperationPrivate *priv;
2583 ModestTnyFolderRules rules;
2584 XFerFolderAsyncHelper *helper;
2586 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2587 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2588 g_return_if_fail (name);
2590 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2592 /* Get account and set it into mail_operation */
2593 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2594 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2596 /* Check folder rules */
2597 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2598 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2600 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2603 TnyFolderStore *into;
2605 into = tny_folder_get_folder_store (folder);
2607 /* Check that the new folder name is not used by any
2608 special local folder */
2609 if (new_name_valid_if_local_account (priv, into, name)) {
2610 /* Create the helper */
2611 helper = g_slice_new0 (XFerFolderAsyncHelper);
2612 helper->mail_op = g_object_ref(self);
2613 helper->user_callback = user_callback;
2614 helper->user_data = user_data;
2616 /* Rename. Camel handles folder subscription/unsubscription */
2617 modest_mail_operation_notify_start (self);
2618 tny_folder_copy_async (folder, into, name, TRUE,
2620 transfer_folder_status_cb,
2622 g_object_unref (into);
2624 g_object_unref (into);
2631 /* Set status failed and set an error */
2632 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2633 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2634 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2635 _("FIXME: unable to rename"));
2638 user_callback (self, NULL, user_data);
2640 /* Notify about operation end */
2641 modest_mail_operation_notify_end (self);
2644 /* ******************************************************************* */
2645 /* ************************** MSG ACTIONS ************************* */
2646 /* ******************************************************************* */
2649 modest_mail_operation_find_msg (ModestMailOperation *self,
2651 const gchar *msg_uid,
2652 gboolean progress_feedback,
2653 GetMsgAsyncUserCallback user_callback,
2656 GetMsgInfo *helper = NULL;
2657 ModestMailOperationPrivate *priv;
2659 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2660 g_return_if_fail (msg_uid != NULL);
2662 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2663 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2667 /* Check memory low */
2668 if (_check_memory_low (self)) {
2670 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2671 modest_mail_operation_notify_end (self);
2675 /* Get account and set it into mail_operation */
2676 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2678 /* Check for cached messages */
2679 if (progress_feedback) {
2680 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2682 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2685 /* Create the helper */
2686 helper = g_slice_new0 (GetMsgInfo);
2687 helper->header = NULL;
2688 helper->mail_op = g_object_ref (self);
2689 helper->user_callback = user_callback;
2690 helper->user_data = user_data;
2691 helper->destroy_notify = NULL;
2692 helper->last_total_bytes = 0;
2693 helper->sum_total_bytes = 0;
2694 helper->total_bytes = 0;
2695 helper->more_msgs = NULL;
2696 helper->get_parts = NULL;
2699 modest_mail_operation_notify_start (self);
2701 /* notify about the start of the operation */
2702 ModestMailOperationState *state;
2703 state = modest_mail_operation_clone_state (self);
2706 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2708 g_slice_free (ModestMailOperationState, state);
2710 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2714 modest_mail_operation_get_msg (ModestMailOperation *self,
2716 gboolean progress_feedback,
2717 GetMsgAsyncUserCallback user_callback,
2720 GetMsgInfo *helper = NULL;
2722 ModestMailOperationPrivate *priv;
2724 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2725 g_return_if_fail (TNY_IS_HEADER (header));
2727 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2728 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2732 /* Check memory low */
2733 if (_check_memory_low (self)) {
2735 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2736 modest_mail_operation_notify_end (self);
2740 /* Get account and set it into mail_operation */
2741 folder = tny_header_get_folder (header);
2742 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2744 /* Check for cached messages */
2745 if (progress_feedback) {
2746 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2747 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2749 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2751 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2754 /* Create the helper */
2755 helper = g_slice_new0 (GetMsgInfo);
2756 helper->header = g_object_ref (header);
2757 helper->mail_op = g_object_ref (self);
2758 helper->user_callback = user_callback;
2759 helper->user_data = user_data;
2760 helper->destroy_notify = NULL;
2761 helper->last_total_bytes = 0;
2762 helper->sum_total_bytes = 0;
2763 helper->total_bytes = tny_header_get_message_size (header);
2764 helper->more_msgs = NULL;
2765 helper->get_parts = NULL;
2768 modest_mail_operation_notify_start (self);
2770 /* notify about the start of the operation */
2771 ModestMailOperationState *state;
2772 state = modest_mail_operation_clone_state (self);
2775 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2777 g_slice_free (ModestMailOperationState, state);
2779 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2781 g_object_unref (G_OBJECT (folder));
2785 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2788 gboolean progress_feedback,
2789 GetMsgAsyncUserCallback user_callback,
2792 GetMsgInfo *helper = NULL;
2794 ModestMailOperationPrivate *priv;
2796 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2797 g_return_if_fail (TNY_IS_HEADER (header));
2799 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2800 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2804 /* Check memory low */
2805 if (_check_memory_low (self)) {
2807 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2808 modest_mail_operation_notify_end (self);
2812 /* Get account and set it into mail_operation */
2813 folder = tny_header_get_folder (header);
2814 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2815 const gchar *acc_name;
2816 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2817 priv->account = modest_tny_account_store_get_server_account
2818 (modest_runtime_get_account_store (),
2820 TNY_ACCOUNT_TYPE_STORE);
2821 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2822 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2824 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2827 /* Check for cached messages */
2828 if (progress_feedback) {
2829 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2830 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2832 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2834 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2837 /* Create the helper */
2838 helper = g_slice_new0 (GetMsgInfo);
2839 helper->header = g_object_ref (header);
2840 helper->mail_op = g_object_ref (self);
2841 helper->user_callback = user_callback;
2842 helper->user_data = user_data;
2843 helper->destroy_notify = NULL;
2844 helper->last_total_bytes = 0;
2845 helper->sum_total_bytes = 0;
2846 helper->total_bytes = tny_header_get_message_size (header);
2847 helper->more_msgs = NULL;
2848 helper->get_parts = tny_list_create_iterator (parts);
2851 modest_mail_operation_notify_start (self);
2853 /* notify about the start of the operation */
2854 ModestMailOperationState *state;
2855 state = modest_mail_operation_clone_state (self);
2858 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2860 g_slice_free (ModestMailOperationState, state);
2862 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2864 g_object_unref (G_OBJECT (folder));
2868 get_msg_status_cb (GObject *obj,
2872 GetMsgInfo *helper = NULL;
2874 g_return_if_fail (status != NULL);
2876 /* Show only the status information we want */
2877 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2880 helper = (GetMsgInfo *) user_data;
2881 g_return_if_fail (helper != NULL);
2883 /* Notify progress */
2884 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2885 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2889 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2892 TnyFolder *folder = NULL;
2894 helper = (GetMsgInfo *) user_data;
2896 if (helper->header) {
2897 folder = tny_header_get_folder (helper->header);
2900 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2902 if (folder) g_object_unref (folder);
2906 get_msg_async_cb (TnyFolder *folder,
2912 GetMsgInfo *info = NULL;
2913 ModestMailOperationPrivate *priv = NULL;
2916 info = (GetMsgInfo *) user_data;
2918 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2921 if (info->more_msgs) {
2922 tny_iterator_next (info->more_msgs);
2923 finished = (tny_iterator_is_done (info->more_msgs));
2924 } else if (info->get_parts) {
2925 tny_iterator_next (info->get_parts);
2926 finished = (tny_iterator_is_done (info->get_parts));
2928 finished = (priv->done == priv->total) ? TRUE : FALSE;
2931 /* If canceled by the user, ignore the error given by Tinymail */
2935 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2937 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2938 priv->error = g_error_copy ((const GError *) err);
2940 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2942 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2943 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2944 "%s", err->message);
2946 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2947 /* Set the success status before calling the user callback */
2948 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2951 if (info->header == NULL && msg)
2952 info->header = tny_msg_get_header (msg);
2954 /* Call the user callback */
2955 if (info->user_callback && (finished || (info->get_parts == NULL)))
2956 info->user_callback (info->mail_op, info->header, canceled,
2957 msg, err, info->user_data);
2959 /* Notify about operation end if this is the last callback */
2961 /* Free user data */
2962 if (info->destroy_notify)
2963 info->destroy_notify (info->user_data);
2965 /* Notify about operation end */
2966 modest_mail_operation_notify_end (info->mail_op);
2970 g_object_unref (info->msg);
2971 if (info->more_msgs)
2972 g_object_unref (info->more_msgs);
2974 g_object_unref (info->header);
2975 g_object_unref (info->mail_op);
2976 g_slice_free (GetMsgInfo, info);
2977 } else if (info->get_parts) {
2978 CamelStream *null_stream;
2979 TnyStream *tny_null_stream;
2982 if (info->msg == NULL && msg != NULL)
2983 info->msg = g_object_ref (msg);
2985 null_stream = camel_stream_null_new ();
2986 tny_null_stream = tny_camel_stream_new (null_stream);
2988 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
2989 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
2990 get_msg_async_get_part_cb,
2993 g_object_unref (tny_null_stream);
2994 g_object_unref (part);
2996 } else if (info->more_msgs) {
2997 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2998 TnyFolder *folder = tny_header_get_folder (header);
3000 g_object_unref (info->header);
3001 info->header = g_object_ref (header);
3003 /* Retrieve the next message */
3004 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
3006 g_object_unref (header);
3007 g_object_unref (folder);
3009 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
3014 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
3015 TnyList *header_list,
3016 GetMsgAsyncUserCallback user_callback,
3018 GDestroyNotify notify)
3020 ModestMailOperationPrivate *priv = NULL;
3022 TnyIterator *iter = NULL;
3023 gboolean has_uncached_messages;
3025 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3027 /* Init mail operation */
3028 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3029 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3031 priv->total = tny_list_get_length(header_list);
3033 /* Check memory low */
3034 if (_check_memory_low (self)) {
3035 if (user_callback) {
3036 TnyHeader *header = NULL;
3039 if (tny_list_get_length (header_list) > 0) {
3040 iter = tny_list_create_iterator (header_list);
3041 header = (TnyHeader *) tny_iterator_get_current (iter);
3042 g_object_unref (iter);
3044 user_callback (self, header, FALSE, NULL, priv->error, user_data);
3046 g_object_unref (header);
3050 /* Notify about operation end */
3051 modest_mail_operation_notify_end (self);
3055 /* Check uncached messages */
3056 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
3057 !has_uncached_messages && !tny_iterator_is_done (iter);
3058 tny_iterator_next (iter)) {
3061 header = (TnyHeader *) tny_iterator_get_current (iter);
3062 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
3063 has_uncached_messages = TRUE;
3064 g_object_unref (header);
3066 g_object_unref (iter);
3067 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
3069 /* Get account and set it into mail_operation */
3070 if (tny_list_get_length (header_list) >= 1) {
3071 TnyIterator *iterator = tny_list_create_iterator (header_list);
3072 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
3074 TnyFolder *folder = tny_header_get_folder (header);
3076 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3077 g_object_unref (folder);
3079 g_object_unref (header);
3081 g_object_unref (iterator);
3084 msg_list_size = compute_message_list_size (header_list, 0);
3086 modest_mail_operation_notify_start (self);
3087 iter = tny_list_create_iterator (header_list);
3088 if (!tny_iterator_is_done (iter)) {
3089 /* notify about the start of the operation */
3090 ModestMailOperationState *state;
3091 state = modest_mail_operation_clone_state (self);
3094 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3097 GetMsgInfo *msg_info = NULL;
3098 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3099 TnyFolder *folder = tny_header_get_folder (header);
3101 /* Create the message info */
3102 msg_info = g_slice_new0 (GetMsgInfo);
3103 msg_info->mail_op = g_object_ref (self);
3104 msg_info->header = g_object_ref (header);
3105 msg_info->more_msgs = g_object_ref (iter);
3106 msg_info->user_callback = user_callback;
3107 msg_info->user_data = user_data;
3108 msg_info->destroy_notify = notify;
3109 msg_info->last_total_bytes = 0;
3110 msg_info->sum_total_bytes = 0;
3111 msg_info->total_bytes = msg_list_size;
3112 msg_info->msg = NULL;
3114 /* The callback will call it per each header */
3115 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3117 /* Free and go on */
3118 g_object_unref (header);
3119 g_object_unref (folder);
3120 g_slice_free (ModestMailOperationState, state);
3122 g_object_unref (iter);
3127 remove_msgs_async_cb (TnyFolder *folder,
3133 const gchar *account_name;
3134 TnyAccount *account;
3135 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3136 ModestMailOperation *self;
3137 ModestMailOperationPrivate *priv;
3138 ModestProtocolRegistry *protocol_registry;
3139 SyncFolderHelper *helper;
3141 self = (ModestMailOperation *) user_data;
3142 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3143 protocol_registry = modest_runtime_get_protocol_registry ();
3145 if (canceled || err) {
3146 /* If canceled by the user, ignore the error given by Tinymail */
3148 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3150 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3151 priv->error = g_error_copy ((const GError *) err);
3152 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3155 modest_mail_operation_notify_end (self);
3156 g_object_unref (self);
3160 account = modest_tny_folder_get_account (folder);
3161 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3162 account_proto = modest_tny_account_get_protocol_type (account);
3163 g_object_unref (account);
3165 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3166 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3176 helper = g_slice_new0 (SyncFolderHelper);
3177 helper->mail_op = g_object_ref (self);
3178 helper->user_callback = NULL;
3179 helper->user_data = NULL;
3182 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3184 /* Remove the extra reference */
3185 g_object_unref (self);
3189 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3191 gboolean remove_to_trash /*ignored*/)
3193 TnyFolder *folder = NULL;
3194 ModestMailOperationPrivate *priv;
3195 TnyIterator *iter = NULL;
3196 TnyHeader *header = NULL;
3197 TnyList *remove_headers = NULL;
3198 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3199 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3201 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3202 g_return_if_fail (TNY_IS_LIST (headers));
3204 if (remove_to_trash)
3205 g_warning ("remove to trash is not implemented");
3207 if (tny_list_get_length(headers) == 0) {
3208 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3209 goto cleanup; /* nothing to do */
3212 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3214 /* Get folder from first header and sync it */
3215 iter = tny_list_create_iterator (headers);
3216 header = TNY_HEADER (tny_iterator_get_current (iter));
3217 g_object_unref (iter);
3219 folder = tny_header_get_folder (header);
3220 if (!TNY_IS_FOLDER(folder)) {
3221 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3225 /* Use the merged folder if we're removing messages from outbox */
3226 if (modest_tny_folder_is_local_folder (folder)) {
3227 ModestTnyLocalFoldersAccount *local_account;
3229 local_account = (ModestTnyLocalFoldersAccount *)
3230 modest_tny_account_store_get_local_folders_account (accstore);
3231 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3232 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3233 g_object_unref (folder);
3234 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3236 g_object_unref (local_account);
3239 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3240 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3242 while (!tny_iterator_is_done (headers_iter)) {
3243 TnyTransportAccount *traccount = NULL;
3244 TnyHeader *hdr = NULL;
3246 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3247 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3250 ModestTnySendQueueStatus status;
3251 ModestTnySendQueue *send_queue;
3253 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3254 if (TNY_IS_SEND_QUEUE (send_queue)) {
3257 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3258 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3259 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3260 if (G_UNLIKELY (remove_headers == NULL))
3261 remove_headers = tny_simple_list_new ();
3262 tny_list_append(remove_headers, G_OBJECT(hdr));
3266 g_object_unref(traccount);
3268 g_object_unref(hdr);
3269 tny_iterator_next (headers_iter);
3271 g_object_unref(headers_iter);
3274 /* Get account and set it into mail_operation */
3275 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3276 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3277 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3279 if (!remove_headers)
3280 remove_headers = g_object_ref (headers);
3282 /* remove message from folder */
3283 modest_mail_operation_notify_start (self);
3284 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3285 NULL, g_object_ref (self));
3289 g_object_unref (remove_headers);
3291 g_object_unref (header);
3293 g_object_unref (folder);
3297 notify_progress_of_multiple_messages (ModestMailOperation *self,
3299 gint *last_total_bytes,
3300 gint *sum_total_bytes,
3302 gboolean increment_done)
3304 ModestMailOperationPrivate *priv;
3305 ModestMailOperationState *state;
3306 gboolean is_num_bytes = FALSE;
3308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3310 /* We know that tinymail sends us information about
3311 * transferred bytes with this particular message
3313 if (status->message)
3314 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3316 state = modest_mail_operation_clone_state (self);
3317 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3318 /* We know that we're in a different message when the
3319 total number of bytes to transfer is different. Of
3320 course it could fail if we're transferring messages
3321 of the same size, but this is a workarround */
3322 if (status->of_total != *last_total_bytes) {
3323 /* We need to increment the done when there is
3324 no information about each individual
3325 message, we need to do this in message
3326 transfers, and we don't do it for getting
3330 *sum_total_bytes += *last_total_bytes;
3331 *last_total_bytes = status->of_total;
3333 state->bytes_done += status->position + *sum_total_bytes;
3334 state->bytes_total = total_bytes;
3336 /* Notify the status change. Only notify about changes
3337 referred to bytes */
3338 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3342 g_slice_free (ModestMailOperationState, state);
3346 transfer_msgs_status_cb (GObject *obj,
3350 XFerMsgsAsyncHelper *helper;
3352 g_return_if_fail (status != NULL);
3354 /* Show only the status information we want */
3355 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3358 helper = (XFerMsgsAsyncHelper *) user_data;
3359 g_return_if_fail (helper != NULL);
3361 /* Notify progress */
3362 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3363 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3367 transfer_msgs_sync_folder_cb (TnyFolder *self,
3372 XFerMsgsAsyncHelper *helper;
3373 /* We don't care here about the results of the
3375 helper = (XFerMsgsAsyncHelper *) user_data;
3377 /* Notify about operation end */
3378 modest_mail_operation_notify_end (helper->mail_op);
3380 /* If user defined callback function was defined, call it */
3381 if (helper->user_callback)
3382 helper->user_callback (helper->mail_op, helper->user_data);
3385 if (helper->more_msgs)
3386 g_object_unref (helper->more_msgs);
3387 if (helper->headers)
3388 g_object_unref (helper->headers);
3389 if (helper->dest_folder)
3390 g_object_unref (helper->dest_folder);
3391 if (helper->mail_op)
3392 g_object_unref (helper->mail_op);
3393 g_slice_free (XFerMsgsAsyncHelper, helper);
3397 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3399 XFerMsgsAsyncHelper *helper;
3400 ModestMailOperation *self;
3401 ModestMailOperationPrivate *priv;
3402 gboolean finished = TRUE;
3404 helper = (XFerMsgsAsyncHelper *) user_data;
3405 self = helper->mail_op;
3407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3410 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3412 priv->error = g_error_copy (err);
3414 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3415 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3416 if (helper->more_msgs) {
3417 /* We'll transfer the next message in the list */
3418 tny_iterator_next (helper->more_msgs);
3419 if (!tny_iterator_is_done (helper->more_msgs)) {
3420 GObject *next_header;
3421 g_object_unref (helper->headers);
3422 helper->headers = tny_simple_list_new ();
3423 next_header = tny_iterator_get_current (helper->more_msgs);
3424 tny_list_append (helper->headers, next_header);
3425 g_object_unref (next_header);
3431 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3436 /* Synchronize the source folder contents. This should
3437 be done by tinymail but the camel_folder_sync it's
3438 actually disabled in transfer_msgs_thread_clean
3439 because it's supposed to cause hangs */
3440 tny_folder_sync_async (folder, helper->delete,
3441 transfer_msgs_sync_folder_cb,
3444 /* Transfer more messages */
3445 tny_folder_transfer_msgs_async (folder,
3447 helper->dest_folder,
3450 transfer_msgs_status_cb,
3455 /* Computes the size of the messages the headers in the list belongs
3456 to. If num_elements is different from 0 then it only takes into
3457 account the first num_elements for the calculation */
3459 compute_message_list_size (TnyList *headers,
3463 guint size = 0, element = 0;
3465 /* If num_elements is not valid then take all into account */
3466 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3467 num_elements = tny_list_get_length (headers);
3469 iter = tny_list_create_iterator (headers);
3470 while (!tny_iterator_is_done (iter) && element < num_elements) {
3471 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3472 size += tny_header_get_message_size (header);
3473 g_object_unref (header);
3474 tny_iterator_next (iter);
3477 g_object_unref (iter);
3483 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3486 gboolean delete_original,
3487 XferMsgsAsyncUserCallback user_callback,
3490 ModestMailOperationPrivate *priv = NULL;
3491 TnyIterator *iter = NULL;
3492 TnyFolder *src_folder = NULL;
3493 XFerMsgsAsyncHelper *helper = NULL;
3494 TnyHeader *header = NULL;
3495 ModestTnyFolderRules rules = 0;
3496 TnyAccount *dst_account = NULL;
3497 gboolean leave_on_server;
3498 ModestMailOperationState *state;
3499 ModestProtocolRegistry *protocol_registry;
3500 ModestProtocolType account_protocol;
3502 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3503 g_return_if_fail (headers && TNY_IS_LIST (headers));
3504 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3506 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3507 protocol_registry = modest_runtime_get_protocol_registry ();
3509 priv->total = tny_list_get_length (headers);
3511 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3512 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3514 /* Apply folder rules */
3515 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3516 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3517 /* Set status failed and set an error */
3518 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3519 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3520 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3521 _CS("ckct_ib_unable_to_paste_here"));
3522 /* Notify the queue */
3523 modest_mail_operation_notify_end (self);
3527 /* Get source folder */
3528 iter = tny_list_create_iterator (headers);
3529 header = TNY_HEADER (tny_iterator_get_current (iter));
3531 src_folder = tny_header_get_folder (header);
3532 g_object_unref (header);
3534 g_object_unref (iter);
3536 if (src_folder == NULL) {
3537 /* Notify the queue */
3538 modest_mail_operation_notify_end (self);
3540 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3545 /* Check folder source and destination */
3546 if (src_folder == folder) {
3547 /* Set status failed and set an error */
3548 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3549 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3550 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3551 _("mail_in_ui_folder_copy_target_error"));
3553 /* Notify the queue */
3554 modest_mail_operation_notify_end (self);
3557 g_object_unref (src_folder);
3561 /* Create the helper */
3562 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3563 helper->mail_op = g_object_ref(self);
3564 helper->dest_folder = g_object_ref(folder);
3565 helper->user_callback = user_callback;
3566 helper->user_data = user_data;
3567 helper->last_total_bytes = 0;
3568 helper->sum_total_bytes = 0;
3569 helper->total_bytes = compute_message_list_size (headers, 0);
3571 /* Get account and set it into mail_operation */
3572 priv->account = modest_tny_folder_get_account (src_folder);
3573 dst_account = modest_tny_folder_get_account (folder);
3575 if (priv->account == dst_account) {
3576 /* Transfer all messages at once using the fast
3577 * method. Note that depending on the server this
3578 * might not be that fast, and might not be
3579 * user-cancellable either */
3580 helper->headers = g_object_ref (headers);
3581 helper->more_msgs = NULL;
3583 /* Transfer messages one by one so the user can cancel
3586 helper->headers = tny_simple_list_new ();
3587 helper->more_msgs = tny_list_create_iterator (headers);
3588 hdr = tny_iterator_get_current (helper->more_msgs);
3589 tny_list_append (helper->headers, hdr);
3590 g_object_unref (hdr);
3593 /* If leave_on_server is set to TRUE then don't use
3594 delete_original, we always pass FALSE. This is because
3595 otherwise tinymail will try to sync the source folder and
3596 this could cause an error if we're offline while
3597 transferring an already downloaded message from a POP
3599 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3600 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3601 const gchar *account_name;
3603 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3604 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3607 leave_on_server = FALSE;
3610 /* Do not delete messages if leave on server is TRUE */
3611 helper->delete = (leave_on_server) ? FALSE : delete_original;
3613 modest_mail_operation_notify_start (self);
3615 /* Start notifying progress */
3616 state = modest_mail_operation_clone_state (self);
3619 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3620 g_slice_free (ModestMailOperationState, state);
3622 tny_folder_transfer_msgs_async (src_folder,
3627 transfer_msgs_status_cb,
3629 g_object_unref (src_folder);
3630 g_object_unref (dst_account);
3635 on_refresh_folder (TnyFolder *folder,
3640 RefreshAsyncHelper *helper = NULL;
3641 ModestMailOperation *self = NULL;
3642 ModestMailOperationPrivate *priv = NULL;
3644 helper = (RefreshAsyncHelper *) user_data;
3645 self = helper->mail_op;
3646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3648 g_return_if_fail(priv!=NULL);
3651 priv->error = g_error_copy (error);
3652 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3657 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3658 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3659 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3660 _("Error trying to refresh the contents of %s"),
3661 tny_folder_get_name (folder));
3665 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3668 /* Call user defined callback, if it exists */
3669 if (helper->user_callback) {
3671 /* This is not a GDK lock because we are a Tinymail callback and
3672 * Tinymail already acquires the Gdk lock */
3673 helper->user_callback (self, folder, helper->user_data);
3677 g_slice_free (RefreshAsyncHelper, helper);
3679 /* Notify about operation end */
3680 modest_mail_operation_notify_end (self);
3681 g_object_unref(self);
3685 on_refresh_folder_status_update (GObject *obj,
3689 RefreshAsyncHelper *helper = NULL;
3690 ModestMailOperation *self = NULL;
3691 ModestMailOperationPrivate *priv = NULL;
3692 ModestMailOperationState *state;
3694 g_return_if_fail (user_data != NULL);
3695 g_return_if_fail (status != NULL);
3697 /* Show only the status information we want */
3698 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3701 helper = (RefreshAsyncHelper *) user_data;
3702 self = helper->mail_op;
3703 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3705 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3707 priv->done = status->position;
3708 priv->total = status->of_total;
3710 state = modest_mail_operation_clone_state (self);
3712 /* This is not a GDK lock because we are a Tinymail callback and
3713 * Tinymail already acquires the Gdk lock */
3714 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3716 g_slice_free (ModestMailOperationState, state);
3720 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3722 RefreshAsyncUserCallback user_callback,
3725 ModestMailOperationPrivate *priv = NULL;
3726 RefreshAsyncHelper *helper = NULL;
3728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3730 /* Check memory low */
3731 if (_check_memory_low (self)) {
3733 user_callback (self, folder, user_data);
3734 /* Notify about operation end */
3735 modest_mail_operation_notify_end (self);
3739 /* Get account and set it into mail_operation */
3740 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3741 priv->account = modest_tny_folder_get_account (folder);
3742 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3744 /* Create the helper */
3745 helper = g_slice_new0 (RefreshAsyncHelper);
3746 helper->mail_op = g_object_ref(self);
3747 helper->user_callback = user_callback;
3748 helper->user_data = user_data;
3750 modest_mail_operation_notify_start (self);
3752 /* notify that the operation was started */
3753 ModestMailOperationState *state;
3754 state = modest_mail_operation_clone_state (self);
3757 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3759 g_slice_free (ModestMailOperationState, state);
3761 tny_folder_refresh_async (folder,
3763 on_refresh_folder_status_update,
3768 run_queue_notify_and_destroy (RunQueueHelper *helper,
3769 ModestMailOperationStatus status)
3771 ModestMailOperationPrivate *priv;
3774 if (helper->error_handler &&
3775 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3776 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3777 if (helper->start_handler &&
3778 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3779 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3780 if (helper->stop_handler &&
3781 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3782 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3785 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3786 priv->status = status;
3789 modest_mail_operation_notify_end (helper->self);
3792 g_object_unref (helper->queue);
3793 g_object_unref (helper->self);
3794 g_slice_free (RunQueueHelper, helper);
3798 run_queue_stop (ModestTnySendQueue *queue,
3801 RunQueueHelper *helper;
3803 g_debug ("%s sending queue stopped", __FUNCTION__);
3805 helper = (RunQueueHelper *) user_data;
3806 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3810 modest_mail_operation_run_queue (ModestMailOperation *self,
3811 ModestTnySendQueue *queue)
3813 ModestMailOperationPrivate *priv;
3814 RunQueueHelper *helper;
3816 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3817 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3818 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3820 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3821 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3822 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3824 /* Create the helper */
3825 helper = g_slice_new0 (RunQueueHelper);
3826 helper->queue = g_object_ref (queue);
3827 helper->self = g_object_ref (self);
3828 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3829 G_CALLBACK (run_queue_stop),
3832 /* Notify operation has started */
3833 modest_mail_operation_notify_start (self);
3834 g_debug ("%s, run queue started", __FUNCTION__);
3838 queue_wakeup_callback (ModestTnySendQueue *queue,
3843 ModestMailOperation *mail_op;
3844 ModestMailOperationPrivate *priv;
3846 mail_op = (ModestMailOperation *) userdata;
3847 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3849 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3850 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3853 modest_mail_operation_notify_end (mail_op);
3854 g_object_unref (mail_op);
3858 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3859 ModestTnySendQueue *queue)
3861 ModestMailOperationPrivate *priv;
3863 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3864 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3865 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3867 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3868 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3869 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3871 g_object_ref (self);
3873 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3874 modest_mail_operation_notify_start (self);
3878 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3880 ModestMailOperation *self = (ModestMailOperation *) userdata;
3881 ModestMailOperationPrivate *priv;
3883 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3884 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3887 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3889 modest_mail_operation_notify_end (self);
3890 g_object_unref (self);
3894 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3896 ModestMailOperationPrivate *priv;
3898 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3899 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3900 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3902 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3904 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3905 priv->account = NULL;
3906 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3908 modest_mail_operation_notify_start (self);
3909 g_object_ref (self);
3910 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3914 sync_folder_finish_callback (TnyFolder *self,
3920 ModestMailOperationPrivate *priv;
3921 SyncFolderHelper *helper;
3923 helper = (SyncFolderHelper *) user_data;
3924 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3926 /* If canceled by the user, ignore the error given by Tinymail */
3928 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3930 /* If the operation was a sync then the status is
3931 failed, but if it's part of another operation then
3932 just set it as finished with errors */
3933 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3934 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3936 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3937 priv->error = g_error_copy ((const GError *) err);
3938 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3940 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3944 if (helper->user_callback)
3945 helper->user_callback (helper->mail_op, self, helper->user_data);
3947 modest_mail_operation_notify_end (helper->mail_op);
3950 g_object_unref (helper->mail_op);
3951 g_slice_free (SyncFolderHelper, helper);
3955 modest_mail_operation_sync_folder (ModestMailOperation *self,
3958 SyncFolderCallback callback,
3961 ModestMailOperationPrivate *priv;
3962 SyncFolderHelper *helper;
3964 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3965 g_return_if_fail (TNY_IS_FOLDER (folder));
3966 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3968 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3969 priv->account = modest_tny_folder_get_account (folder);
3970 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3973 helper = g_slice_new0 (SyncFolderHelper);
3974 helper->mail_op = g_object_ref (self);
3975 helper->user_callback = callback;
3976 helper->user_data = user_data;
3978 modest_mail_operation_notify_start (self);
3979 tny_folder_sync_async (folder, expunge,
3980 (TnyFolderCallback) sync_folder_finish_callback,
3985 modest_mail_operation_notify_start (ModestMailOperation *self)
3987 ModestMailOperationPrivate *priv = NULL;
3989 g_return_if_fail (self);
3991 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3993 /* Ensure that all the fields are filled correctly */
3994 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3996 /* Notify the observers about the mail operation. We do not
3997 wrapp this emission because we assume that this function is
3998 always called from within the main lock */
3999 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
4004 * It's used by the mail operation queue to notify the observers
4005 * attached to that signal that the operation finished. We need to use
4006 * that because tinymail does not give us the progress of a given
4007 * operation when it finishes (it directly calls the operation
4011 modest_mail_operation_notify_end (ModestMailOperation *self)
4013 ModestMailOperationPrivate *priv = NULL;
4015 g_return_if_fail (self);
4017 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4019 /* Notify the observers about the mail operation end. We do
4020 not wrapp this emission because we assume that this
4021 function is always called from within the main lock */
4022 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
4024 /* Remove the error user data */
4025 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
4026 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
4030 modest_mail_operation_get_account (ModestMailOperation *self)
4032 ModestMailOperationPrivate *priv = NULL;
4034 g_return_val_if_fail (self, NULL);
4036 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4038 return (priv->account) ? g_object_ref (priv->account) : NULL;
4042 modest_mail_operation_noop (ModestMailOperation *self)
4044 ModestMailOperationPrivate *priv = NULL;
4046 g_return_if_fail (self);
4048 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4049 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4050 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
4054 /* This mail operation does nothing actually */
4055 modest_mail_operation_notify_start (self);
4056 modest_mail_operation_notify_end (self);
4061 modest_mail_operation_to_string (ModestMailOperation *self)
4063 const gchar *type, *status, *account_id;
4064 ModestMailOperationPrivate *priv = NULL;
4066 g_return_val_if_fail (self, NULL);
4068 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4070 /* new operations don't have anything interesting */
4071 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
4072 return g_strdup_printf ("%p <new operation>", self);
4074 switch (priv->op_type) {
4075 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
4076 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
4077 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
4078 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
4079 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
4080 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
4081 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
4082 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
4083 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
4084 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
4085 default: type = "UNEXPECTED"; break;
4088 switch (priv->status) {
4089 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4090 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4091 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4092 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4093 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4094 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4095 default: status= "UNEXPECTED"; break;
4098 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4100 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4101 priv->done, priv->total,
4102 priv->error && priv->error->message ? priv->error->message : "");
4106 * Once the mail operations were objects this will be no longer
4107 * needed. I don't like it, but we need it for the moment
4110 _check_memory_low (ModestMailOperation *mail_op)
4112 if (modest_platform_check_memory_low (NULL, FALSE)) {
4113 ModestMailOperationPrivate *priv;
4115 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4116 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4117 g_set_error (&(priv->error),
4118 MODEST_MAIL_OPERATION_ERROR,
4119 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4120 "Not enough memory to complete the operation");