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>
75 * Remove all these #ifdef stuff when the tinymail's idle calls become
78 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
80 /* 'private'/'protected' functions */
81 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
82 static void modest_mail_operation_init (ModestMailOperation *obj);
83 static void modest_mail_operation_finalize (GObject *obj);
85 static void get_msg_async_cb (TnyFolder *folder,
91 static void get_msg_status_cb (GObject *obj,
95 static void modest_mail_operation_notify_start (ModestMailOperation *self);
96 static void modest_mail_operation_notify_end (ModestMailOperation *self);
98 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
100 gint *last_total_bytes,
101 gint *sum_total_bytes,
103 gboolean increment_done);
105 static guint compute_message_list_size (TnyList *headers, guint num_elements);
107 static int compare_headers_by_date (gconstpointer a,
110 static void sync_folder_finish_callback (TnyFolder *self,
115 static gboolean _check_memory_low (ModestMailOperation *mail_op);
119 ModestTnySendQueue *queue;
120 ModestMailOperation *self;
126 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
127 ModestMailOperationStatus status);
129 /* Helpers for the update account operation (send & receive)*/
132 ModestMailOperation *mail_op;
134 UpdateAccountCallback callback;
139 TnyFolderObserver *inbox_observer;
140 gboolean interactive;
144 static void destroy_update_account_info (UpdateAccountInfo *info);
146 static void update_account_send_mail (UpdateAccountInfo *info);
148 static void update_account_get_msg_async_cb (TnyFolder *folder,
154 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
155 TnyList *new_headers);
157 enum _ModestMailOperationSignals
159 PROGRESS_CHANGED_SIGNAL,
160 OPERATION_STARTED_SIGNAL,
161 OPERATION_FINISHED_SIGNAL,
165 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
166 struct _ModestMailOperationPrivate {
172 ErrorCheckingUserCallback error_checking;
173 gpointer error_checking_user_data;
174 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
175 ModestMailOperationStatus status;
176 ModestMailOperationTypeOperation op_type;
179 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
180 MODEST_TYPE_MAIL_OPERATION, \
181 ModestMailOperationPrivate))
183 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
184 priv->status = new_status;\
189 GetMsgAsyncUserCallback user_callback;
191 TnyIterator *more_msgs;
193 ModestMailOperation *mail_op;
194 GDestroyNotify destroy_notify;
195 gint last_total_bytes;
196 gint sum_total_bytes;
198 TnyIterator *get_parts;
202 typedef struct _RefreshAsyncHelper {
203 ModestMailOperation *mail_op;
204 RefreshAsyncUserCallback user_callback;
206 } RefreshAsyncHelper;
208 typedef struct _XFerMsgsAsyncHelper
210 ModestMailOperation *mail_op;
212 TnyIterator *more_msgs;
213 TnyFolder *dest_folder;
214 XferMsgsAsyncUserCallback user_callback;
217 gint last_total_bytes;
218 gint sum_total_bytes;
220 } XFerMsgsAsyncHelper;
222 typedef struct _XFerFolderAsyncHelper
224 ModestMailOperation *mail_op;
225 XferFolderAsyncUserCallback user_callback;
227 } XFerFolderAsyncHelper;
229 typedef struct _SyncFolderHelper {
230 ModestMailOperation *mail_op;
231 SyncFolderCallback user_callback;
235 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
239 static void modest_mail_operation_create_msg (ModestMailOperation *self,
240 const gchar *from, const gchar *to,
241 const gchar *cc, const gchar *bcc,
242 const gchar *subject, const gchar *plain_body,
243 const gchar *html_body, const GList *attachments_list,
244 const GList *images_list,
245 TnyHeaderFlags priority_flags,
246 const gchar *references, const gchar *in_reply_to,
247 ModestMailOperationCreateMsgCallback callback,
250 static gboolean idle_notify_queue (gpointer data);
253 ModestMailOperation *mail_op;
263 GList *attachments_list;
265 TnyHeaderFlags priority_flags;
266 ModestMailOperationCreateMsgCallback callback;
272 ModestMailOperation *mail_op;
274 ModestMailOperationCreateMsgCallback callback;
279 static GObjectClass *parent_class = NULL;
281 static guint signals[NUM_SIGNALS] = {0};
284 modest_mail_operation_get_type (void)
286 static GType my_type = 0;
288 static const GTypeInfo my_info = {
289 sizeof(ModestMailOperationClass),
290 NULL, /* base init */
291 NULL, /* base finalize */
292 (GClassInitFunc) modest_mail_operation_class_init,
293 NULL, /* class finalize */
294 NULL, /* class data */
295 sizeof(ModestMailOperation),
297 (GInstanceInitFunc) modest_mail_operation_init,
300 my_type = g_type_register_static (G_TYPE_OBJECT,
301 "ModestMailOperation",
308 modest_mail_operation_class_init (ModestMailOperationClass *klass)
310 GObjectClass *gobject_class;
311 gobject_class = (GObjectClass*) klass;
313 parent_class = g_type_class_peek_parent (klass);
314 gobject_class->finalize = modest_mail_operation_finalize;
316 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
319 * ModestMailOperation::progress-changed
320 * @self: the #MailOperation that emits the signal
321 * @user_data: user data set when the signal handler was connected
323 * Emitted when the progress of a mail operation changes
325 signals[PROGRESS_CHANGED_SIGNAL] =
326 g_signal_new ("progress-changed",
327 G_TYPE_FROM_CLASS (gobject_class),
329 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
331 g_cclosure_marshal_VOID__POINTER,
332 G_TYPE_NONE, 1, G_TYPE_POINTER);
336 * This signal is issued whenever a mail operation starts, and
337 * starts mean when the tinymail operation is issued. This
338 * means that it could happen that something wrong happens and
339 * the tinymail function is never called. In this situation a
340 * operation-finished will be issued without any
343 signals[OPERATION_STARTED_SIGNAL] =
344 g_signal_new ("operation-started",
345 G_TYPE_FROM_CLASS (gobject_class),
347 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
349 g_cclosure_marshal_VOID__VOID,
354 * This signal is issued whenever a mail operation
355 * finishes. Note that this signal could be issued without any
356 * previous "operation-started" signal, because this last one
357 * is only issued when the tinymail operation is successfully
360 signals[OPERATION_FINISHED_SIGNAL] =
361 g_signal_new ("operation-finished",
362 G_TYPE_FROM_CLASS (gobject_class),
364 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
366 g_cclosure_marshal_VOID__VOID,
371 modest_mail_operation_init (ModestMailOperation *obj)
373 ModestMailOperationPrivate *priv;
375 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
377 priv->account = NULL;
378 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
379 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
384 priv->error_checking = NULL;
385 priv->error_checking_user_data = NULL;
389 modest_mail_operation_finalize (GObject *obj)
391 ModestMailOperationPrivate *priv;
393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
398 g_error_free (priv->error);
402 g_object_unref (priv->source);
406 g_object_unref (priv->account);
407 priv->account = NULL;
411 G_OBJECT_CLASS(parent_class)->finalize (obj);
415 modest_mail_operation_new (GObject *source)
417 ModestMailOperation *obj;
418 ModestMailOperationPrivate *priv;
420 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
421 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
424 priv->source = g_object_ref(source);
430 modest_mail_operation_new_with_error_handling (GObject *source,
431 ErrorCheckingUserCallback error_handler,
433 ErrorCheckingUserDataDestroyer error_handler_destroyer)
435 ModestMailOperation *obj;
436 ModestMailOperationPrivate *priv;
438 obj = modest_mail_operation_new (source);
439 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
441 g_return_val_if_fail (error_handler != NULL, obj);
442 priv->error_checking = error_handler;
443 priv->error_checking_user_data = user_data;
444 priv->error_checking_user_data_destroyer = error_handler_destroyer;
450 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
452 ModestMailOperationPrivate *priv;
454 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
456 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
457 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
459 /* Call the user callback */
460 if (priv->error_checking != NULL)
461 priv->error_checking (self, priv->error_checking_user_data);
465 ModestMailOperationTypeOperation
466 modest_mail_operation_get_type_operation (ModestMailOperation *self)
468 ModestMailOperationPrivate *priv;
470 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
471 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
475 return priv->op_type;
479 modest_mail_operation_is_mine (ModestMailOperation *self,
482 ModestMailOperationPrivate *priv;
484 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
487 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
488 if (priv->source == NULL) return FALSE;
490 return priv->source == me;
494 modest_mail_operation_get_source (ModestMailOperation *self)
496 ModestMailOperationPrivate *priv;
498 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
501 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
503 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
507 return (priv->source) ? g_object_ref (priv->source) : NULL;
510 ModestMailOperationStatus
511 modest_mail_operation_get_status (ModestMailOperation *self)
513 ModestMailOperationPrivate *priv;
515 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
516 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
517 MODEST_MAIL_OPERATION_STATUS_INVALID);
519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
521 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
522 return MODEST_MAIL_OPERATION_STATUS_INVALID;
529 modest_mail_operation_get_error (ModestMailOperation *self)
531 ModestMailOperationPrivate *priv;
533 g_return_val_if_fail (self, NULL);
534 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
539 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
547 modest_mail_operation_cancel (ModestMailOperation *self)
549 ModestMailOperationPrivate *priv;
550 gboolean canceled = FALSE;
552 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
554 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
557 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
559 /* Cancel the mail operation */
560 g_return_val_if_fail (priv->account, FALSE);
561 tny_account_cancel (priv->account);
563 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
564 ModestTnySendQueue *queue;
565 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
568 /* Cancel the sending of the following next messages */
569 if (TNY_IS_SEND_QUEUE (queue))
570 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
577 modest_mail_operation_get_task_done (ModestMailOperation *self)
579 ModestMailOperationPrivate *priv;
581 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
589 modest_mail_operation_get_task_total (ModestMailOperation *self)
591 ModestMailOperationPrivate *priv;
593 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
601 modest_mail_operation_is_finished (ModestMailOperation *self)
603 ModestMailOperationPrivate *priv;
604 gboolean retval = FALSE;
606 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
609 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
611 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
612 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
613 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
614 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
624 * Creates an image of the current state of a mail operation, the
625 * caller must free it
627 static ModestMailOperationState *
628 modest_mail_operation_clone_state (ModestMailOperation *self)
630 ModestMailOperationState *state;
631 ModestMailOperationPrivate *priv;
633 g_return_val_if_fail (self, NULL);
634 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
635 g_return_val_if_fail (priv, NULL);
640 state = g_slice_new (ModestMailOperationState);
642 state->status = priv->status;
643 state->op_type = priv->op_type;
644 state->done = priv->done;
645 state->total = priv->total;
646 state->finished = modest_mail_operation_is_finished (self);
647 state->bytes_done = 0;
648 state->bytes_total = 0;
653 /* ******************************************************************* */
654 /* ************************** SEND ACTIONS ************************* */
655 /* ******************************************************************* */
659 ModestMailOperation *mail_op;
664 send_mail_on_sync_async_cb (TnyFolder *folder,
669 ModestMailOperationPrivate *priv;
670 ModestMailOperation *self;
671 SendNewMailHelper *helper;
673 helper = (SendNewMailHelper *) user_data;
674 self = helper->mail_op;
675 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
682 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
683 "Error adding a msg to the send queue\n");
684 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
686 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
691 modest_mail_operation_notify_end (self);
693 g_object_unref (helper->mail_op);
694 g_slice_free (SendNewMailHelper, helper);
698 run_queue_start (TnySendQueue *self,
701 RunQueueHelper *helper = (RunQueueHelper *) user_data;
702 ModestMailOperation *mail_op;
704 g_debug ("%s sending queue successfully started", __FUNCTION__);
706 /* Wait for the message to be sent */
707 mail_op = modest_mail_operation_new (NULL);
708 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
710 modest_mail_operation_run_queue (mail_op, helper->queue);
711 g_object_unref (mail_op);
713 /* Free the helper and end operation */
714 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
718 run_queue_error_happened (TnySendQueue *queue,
724 RunQueueHelper *helper = (RunQueueHelper *) user_data;
725 ModestMailOperationPrivate *priv;
727 /* If we are here this means that the send queue could not
728 start to send emails. Shouldn't happen as this means that
729 we could not create the thread */
730 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
732 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
733 priv->error = g_error_copy ((const GError *) error);
735 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
736 /* This code is here for safety reasons. It should
737 never be called, because that would mean that we
738 are not controlling some error case */
739 g_warning ("%s Error %s should not happen",
740 __FUNCTION__, error->message);
743 /* Free helper and end operation */
744 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
748 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
754 ModestMailOperationPrivate *priv;
755 ModestMailOperation *self;
756 SendNewMailHelper *helper;
758 helper = (SendNewMailHelper *) user_data;
759 self = helper->mail_op;
760 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
766 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
767 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
768 "Error adding a msg to the send queue\n");
769 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
771 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
775 if (helper->notify) {
776 TnyTransportAccount *trans_account;
777 ModestTnySendQueue *queue;
779 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
781 queue = modest_runtime_get_send_queue (trans_account, TRUE);
783 RunQueueHelper *helper;
785 /* Create the helper */
786 helper = g_slice_new0 (RunQueueHelper);
787 helper->queue = g_object_ref (queue);
788 helper->self = g_object_ref (self);
790 /* if sending is ongoing wait for the queue to
791 stop. Otherwise wait for the queue-start
792 signal. It could happen that the queue
793 could not start, then check also the error
795 if (modest_tny_send_queue_sending_in_progress (queue)) {
796 run_queue_start (TNY_SEND_QUEUE (queue), helper);
798 helper->start_handler = g_signal_connect (queue, "queue-start",
799 G_CALLBACK (run_queue_start),
801 helper->error_handler = g_signal_connect (queue, "error-happened",
802 G_CALLBACK (run_queue_error_happened),
806 /* Finalize this mail operation */
807 modest_mail_operation_notify_end (self);
809 g_object_unref (trans_account);
811 g_warning ("No transport account for the operation");
815 g_object_unref (helper->mail_op);
816 g_slice_free (SendNewMailHelper, helper);
820 idle_create_msg_cb (gpointer idle_data)
822 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
824 /* This is a GDK lock because we are an idle callback and
825 * info->callback can contain Gtk+ code */
827 gdk_threads_enter (); /* CHECKED */
828 info->callback (info->mail_op, info->msg, info->userdata);
830 g_object_unref (info->mail_op);
832 g_object_unref (info->msg);
833 g_slice_free (CreateMsgIdleInfo, info);
834 gdk_threads_leave (); /* CHECKED */
840 create_msg_thread (gpointer thread_data)
842 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
843 TnyMsg *new_msg = NULL;
844 ModestMailOperationPrivate *priv;
847 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
848 if (info->html_body == NULL) {
849 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
850 info->bcc, info->subject,
851 info->references, info->in_reply_to,
853 info->attachments_list, &attached,
856 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
857 info->bcc, info->subject,
858 info->references, info->in_reply_to,
860 info->plain_body, info->attachments_list,
861 info->images_list, &attached,
868 /* Set priority flags in message */
869 header = tny_msg_get_header (new_msg);
870 tny_header_set_flag (header, info->priority_flags);
872 /* Set attachment flags in message */
873 if (info->attachments_list != NULL && attached > 0)
874 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
876 g_object_unref (G_OBJECT(header));
878 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
881 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
882 "modest: failed to create a new msg\n");
890 g_free (info->plain_body);
891 g_free (info->html_body);
892 g_free (info->subject);
893 g_free (info->references);
894 g_free (info->in_reply_to);
895 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
896 g_list_free (info->attachments_list);
897 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
898 g_list_free (info->images_list);
900 if (info->callback) {
901 CreateMsgIdleInfo *idle_info;
902 idle_info = g_slice_new0 (CreateMsgIdleInfo);
903 idle_info->mail_op = g_object_ref (info->mail_op);
904 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
905 idle_info->callback = info->callback;
906 idle_info->userdata = info->userdata;
907 g_idle_add (idle_create_msg_cb, idle_info);
909 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
912 g_object_unref (info->mail_op);
913 g_slice_free (CreateMsgInfo, info);
914 if (new_msg) g_object_unref(new_msg);
920 modest_mail_operation_create_msg (ModestMailOperation *self,
921 const gchar *from, const gchar *to,
922 const gchar *cc, const gchar *bcc,
923 const gchar *subject, const gchar *plain_body,
924 const gchar *html_body,
925 const GList *attachments_list,
926 const GList *images_list,
927 TnyHeaderFlags priority_flags,
928 const gchar *references,
929 const gchar *in_reply_to,
930 ModestMailOperationCreateMsgCallback callback,
933 CreateMsgInfo *info = NULL;
935 info = g_slice_new0 (CreateMsgInfo);
936 info->mail_op = g_object_ref (self);
938 info->from = g_strdup (from);
939 info->to = g_strdup (to);
940 info->cc = g_strdup (cc);
941 info->bcc = g_strdup (bcc);
942 info->subject = g_strdup (subject);
943 info->plain_body = g_strdup (plain_body);
944 info->html_body = g_strdup (html_body);
945 info->references = g_strdup (references);
946 info->in_reply_to = g_strdup (in_reply_to);
947 info->attachments_list = g_list_copy ((GList *) attachments_list);
948 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
949 info->images_list = g_list_copy ((GList *) images_list);
950 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
951 info->priority_flags = priority_flags;
953 info->callback = callback;
954 info->userdata = userdata;
956 g_thread_create (create_msg_thread, info, FALSE, NULL);
961 TnyTransportAccount *transport_account;
966 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
970 TnySendQueue *send_queue = NULL;
971 ModestMailOperationPrivate *priv = NULL;
972 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
973 TnyFolder *draft_folder = NULL;
974 TnyFolder *outbox_folder = NULL;
975 TnyHeader *header = NULL;
977 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
980 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
981 modest_mail_operation_notify_end (self);
985 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
986 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
987 modest_mail_operation_notify_end (self);
991 /* Add message to send queue */
992 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
993 if (!TNY_IS_SEND_QUEUE(send_queue)) {
995 g_error_free (priv->error);
998 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
999 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1000 "modest: could not find send queue for account\n");
1001 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1002 modest_mail_operation_notify_end (self);
1005 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
1006 helper->mail_op = g_object_ref (self);
1007 helper->notify = (info->draft_msg == NULL);
1009 /* Add the msg to the queue. The callback will free
1011 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1013 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1017 if (info->draft_msg != NULL) {
1018 TnyList *tmp_headers = NULL;
1019 TnyFolder *folder = NULL;
1020 TnyFolder *src_folder = NULL;
1021 TnyFolderType folder_type;
1022 TnyTransportAccount *transport_account = NULL;
1023 SendNewMailHelper *helper = NULL;
1025 /* To remove the old mail from its source folder, we need to get the
1026 * transport account of the original draft message (the transport account
1027 * might have been changed by the user) */
1028 header = tny_msg_get_header (info->draft_msg);
1029 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1030 modest_runtime_get_account_store(), header);
1031 if (transport_account == NULL)
1032 transport_account = g_object_ref(info->transport_account);
1033 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1034 TNY_FOLDER_TYPE_DRAFTS);
1035 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1036 TNY_FOLDER_TYPE_OUTBOX);
1037 g_object_unref(transport_account);
1039 if (!draft_folder) {
1040 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1042 modest_mail_operation_notify_end (self);
1045 if (!outbox_folder) {
1046 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1048 modest_mail_operation_notify_end (self);
1052 folder = tny_msg_get_folder (info->draft_msg);
1053 if (folder == NULL) {
1054 modest_mail_operation_notify_end (self);
1057 folder_type = modest_tny_folder_guess_folder_type (folder);
1059 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1060 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1062 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1063 src_folder = outbox_folder;
1065 src_folder = draft_folder;
1067 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1068 * because this function requires it to have a UID. */
1069 helper = g_slice_new (SendNewMailHelper);
1070 helper->mail_op = g_object_ref (self);
1071 helper->notify = TRUE;
1073 tmp_headers = tny_simple_list_new ();
1074 tny_list_append (tmp_headers, (GObject*) header);
1075 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1076 g_object_unref (tmp_headers);
1077 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1079 g_object_unref (folder);
1084 g_object_unref (header);
1085 if (info->draft_msg)
1086 g_object_unref (info->draft_msg);
1088 g_object_unref (draft_folder);
1090 g_object_unref (outbox_folder);
1091 if (info->transport_account)
1092 g_object_unref (info->transport_account);
1093 g_slice_free (SendNewMailInfo, info);
1097 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1098 TnyTransportAccount *transport_account,
1100 const gchar *from, const gchar *to,
1101 const gchar *cc, const gchar *bcc,
1102 const gchar *subject, const gchar *plain_body,
1103 const gchar *html_body,
1104 const GList *attachments_list,
1105 const GList *images_list,
1106 const gchar *references,
1107 const gchar *in_reply_to,
1108 TnyHeaderFlags priority_flags)
1110 ModestMailOperationPrivate *priv = NULL;
1111 SendNewMailInfo *info;
1113 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1114 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1116 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1117 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1118 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1119 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1121 modest_mail_operation_notify_start (self);
1123 /* Check parametters */
1125 /* Set status failed and set an error */
1126 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1127 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1128 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1129 _("Error trying to send a mail. You need to set at least one recipient"));
1130 modest_mail_operation_notify_end (self);
1133 info = g_slice_new0 (SendNewMailInfo);
1134 info->transport_account = transport_account;
1135 if (transport_account)
1136 g_object_ref (transport_account);
1137 info->draft_msg = draft_msg;
1139 g_object_ref (draft_msg);
1142 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1143 attachments_list, images_list, priority_flags,
1144 references, in_reply_to,
1145 modest_mail_operation_send_new_mail_cb, info);
1151 ModestMailOperation *mailop;
1153 SaveToDraftstCallback callback;
1155 } FinishSaveRemoteDraftInfo;
1158 finish_save_remote_draft (ModestAccountProtocol *protocol,
1160 const gchar *account_id,
1161 TnyMsg *new_remote_msg,
1166 FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
1167 ModestMailOperationPrivate *priv = NULL;
1169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1171 if (!priv->error && err != NULL) {
1172 /* Priority for errors in save to local stage */
1173 priv->error = g_error_copy (err);
1174 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1178 info->callback (info->mailop, info->msg, info->userdata);
1181 g_object_unref (info->msg);
1183 modest_mail_operation_notify_end (info->mailop);
1184 g_object_unref (info->mailop);
1186 g_slice_free (FinishSaveRemoteDraftInfo, info);
1191 TnyTransportAccount *transport_account;
1193 SaveToDraftstCallback callback;
1197 ModestMailOperation *mailop;
1198 } SaveToDraftsAddMsgInfo;
1201 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1206 ModestMailOperationPrivate *priv = NULL;
1207 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1208 GError *io_error = NULL;
1209 gboolean callback_called = FALSE;
1211 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1213 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1214 io_error = priv->error;
1218 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1219 g_error_free(priv->error);
1222 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1224 if ((!priv->error) && (info->draft_msg != NULL)) {
1225 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1226 TnyFolder *src_folder = tny_header_get_folder (header);
1228 g_debug ("--- REMOVE AND SYNC");
1229 /* Remove the old draft */
1230 tny_folder_remove_msg (src_folder, header, NULL);
1232 /* Synchronize to expunge and to update the msg counts */
1233 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1234 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1235 g_debug ("--- REMOVED - SYNCED");
1237 g_object_unref (G_OBJECT(header));
1238 g_object_unref (G_OBJECT(src_folder));
1242 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1244 g_error_free (io_error);
1247 } else if (io_error) {
1248 priv->error = io_error;
1249 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1251 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1254 if (info->transport_account) {
1255 ModestProtocolType transport_protocol_type;
1256 ModestProtocol *transport_protocol;
1258 transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
1260 transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1261 transport_protocol_type);
1262 if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
1263 FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
1264 srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
1265 srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
1266 srd_info->callback = info->callback;
1267 srd_info->userdata = info->user_data;
1268 modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol),
1269 tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
1270 info->msg, info->draft_msg,
1271 finish_save_remote_draft,
1274 callback_called = TRUE;
1278 /* Call the user callback */
1279 if (!callback_called && info->callback)
1280 info->callback (info->mailop, info->msg, info->user_data);
1282 if (info->transport_account)
1283 g_object_unref (G_OBJECT(info->transport_account));
1284 if (info->draft_msg)
1285 g_object_unref (G_OBJECT (info->draft_msg));
1287 g_object_unref (G_OBJECT(info->drafts));
1289 g_object_unref (G_OBJECT (info->msg));
1291 if (!callback_called)
1292 modest_mail_operation_notify_end (info->mailop);
1294 g_object_unref(info->mailop);
1295 g_slice_free (SaveToDraftsAddMsgInfo, info);
1300 TnyTransportAccount *transport_account;
1302 SaveToDraftstCallback callback;
1307 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1311 TnyFolder *drafts = NULL;
1312 ModestMailOperationPrivate *priv = NULL;
1313 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1315 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1318 if (!(priv->error)) {
1319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1320 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1321 "modest: failed to create a new msg\n");
1324 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1325 TNY_FOLDER_TYPE_DRAFTS);
1326 if (!drafts && !(priv->error)) {
1327 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1328 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1329 "modest: failed to create a new msg\n");
1333 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1335 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1336 cb_info->transport_account = g_object_ref(info->transport_account);
1337 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1338 cb_info->callback = info->callback;
1339 cb_info->user_data = info->user_data;
1340 cb_info->drafts = g_object_ref(drafts);
1341 cb_info->msg = g_object_ref(msg);
1342 cb_info->mailop = g_object_ref(self);
1343 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1347 /* Call the user callback */
1348 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1350 info->callback (self, msg, info->user_data);
1351 modest_mail_operation_notify_end (self);
1355 g_object_unref (G_OBJECT(drafts));
1356 if (info->draft_msg)
1357 g_object_unref (G_OBJECT (info->draft_msg));
1358 if (info->transport_account)
1359 g_object_unref (G_OBJECT(info->transport_account));
1360 g_slice_free (SaveToDraftsInfo, info);
1364 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1365 TnyTransportAccount *transport_account,
1367 const gchar *from, const gchar *to,
1368 const gchar *cc, const gchar *bcc,
1369 const gchar *subject, const gchar *plain_body,
1370 const gchar *html_body,
1371 const GList *attachments_list,
1372 const GList *images_list,
1373 TnyHeaderFlags priority_flags,
1374 const gchar *references,
1375 const gchar *in_reply_to,
1376 SaveToDraftstCallback callback,
1379 ModestMailOperationPrivate *priv = NULL;
1380 SaveToDraftsInfo *info = NULL;
1382 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1383 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1387 /* Get account and set it into mail_operation */
1388 priv->account = g_object_ref (transport_account);
1389 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1391 info = g_slice_new0 (SaveToDraftsInfo);
1392 info->transport_account = g_object_ref (transport_account);
1393 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1394 info->callback = callback;
1395 info->user_data = user_data;
1397 g_debug ("--- CREATE MESSAGE");
1398 modest_mail_operation_notify_start (self);
1399 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1400 attachments_list, images_list, priority_flags,
1401 references, in_reply_to,
1402 modest_mail_operation_save_to_drafts_cb, info);
1407 ModestMailOperation *mail_op;
1408 TnyMimePart *mime_part;
1410 GetMimePartSizeCallback callback;
1412 } GetMimePartSizeInfo;
1414 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1415 /* We use this folder observer to track the headers that have been
1416 * added to a folder */
1419 TnyList *new_headers;
1420 } InternalFolderObserver;
1423 GObjectClass parent;
1424 } InternalFolderObserverClass;
1426 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1428 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1429 internal_folder_observer,
1431 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1435 foreach_add_item (gpointer header, gpointer user_data)
1437 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1440 /* This is the method that looks for new messages in a folder */
1442 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1444 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1446 TnyFolderChangeChanged changed;
1448 changed = tny_folder_change_get_changed (change);
1450 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1453 /* Get added headers */
1454 list = tny_simple_list_new ();
1455 tny_folder_change_get_added_headers (change, list);
1457 /* Add them to the folder observer */
1458 tny_list_foreach (list, foreach_add_item,
1459 derived->new_headers);
1461 g_object_unref (G_OBJECT (list));
1466 internal_folder_observer_init (InternalFolderObserver *self)
1468 self->new_headers = tny_simple_list_new ();
1471 internal_folder_observer_finalize (GObject *object)
1473 InternalFolderObserver *self;
1475 self = (InternalFolderObserver *) object;
1476 g_object_unref (self->new_headers);
1478 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1481 tny_folder_observer_init (TnyFolderObserverIface *iface)
1483 iface->update = internal_folder_observer_update;
1486 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1488 GObjectClass *object_class;
1490 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1491 object_class = (GObjectClass*) klass;
1492 object_class->finalize = internal_folder_observer_finalize;
1496 destroy_update_account_info (UpdateAccountInfo *info)
1498 g_free (info->account_name);
1499 g_object_unref (info->folders);
1500 g_object_unref (info->mail_op);
1501 g_slice_free (UpdateAccountInfo, info);
1506 update_account_send_mail (UpdateAccountInfo *info)
1508 TnyTransportAccount *transport_account = NULL;
1509 ModestTnyAccountStore *account_store;
1511 account_store = modest_runtime_get_account_store ();
1513 /* We don't try to send messages while sending mails is blocked */
1514 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1517 /* Get the transport account */
1518 transport_account = (TnyTransportAccount *)
1519 modest_tny_account_store_get_server_account (account_store, info->account_name,
1520 TNY_ACCOUNT_TYPE_TRANSPORT);
1522 if (transport_account) {
1523 ModestTnySendQueue *send_queue;
1527 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1528 g_object_unref (transport_account);
1530 if (TNY_IS_SEND_QUEUE (send_queue)) {
1531 /* Get outbox folder */
1532 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1533 if (outbox) { /* this could fail in some cases */
1534 num_messages = tny_folder_get_all_count (outbox);
1535 g_object_unref (outbox);
1537 g_warning ("%s: could not get outbox", __FUNCTION__);
1541 if (num_messages != 0) {
1542 ModestMailOperation *mail_op;
1543 /* Reenable suspended items */
1544 mail_op = modest_mail_operation_new (NULL);
1545 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1547 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1550 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1558 update_account_get_msg_async_cb (TnyFolder *folder,
1564 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1565 ModestMailOperationPrivate *priv;
1567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1570 if (TNY_IS_MSG (msg)) {
1571 TnyHeader *header = tny_msg_get_header (msg);
1574 ModestMailOperationState *state;
1575 state = modest_mail_operation_clone_state (msg_info->mail_op);
1576 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1577 state->bytes_done = msg_info->sum_total_bytes;
1578 state->bytes_total = msg_info->total_bytes;
1580 /* Notify the status change. Only notify about changes
1581 referred to bytes */
1582 g_signal_emit (G_OBJECT (msg_info->mail_op),
1583 signals[PROGRESS_CHANGED_SIGNAL],
1586 g_object_unref (header);
1587 g_slice_free (ModestMailOperationState, state);
1591 if (priv->done == priv->total) {
1592 TnyList *new_headers;
1593 UpdateAccountInfo *info;
1595 /* After getting all the messages send the ones in the
1597 info = (UpdateAccountInfo *) msg_info->user_data;
1598 update_account_send_mail (info);
1600 /* Check if the operation was a success */
1602 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1604 /* Call the user callback and free */
1605 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1606 update_account_notify_user_and_free (info, new_headers);
1608 /* Delete the helper */
1610 g_object_unref (msg_info->msg);
1611 g_object_unref (msg_info->more_msgs);
1612 g_object_unref (msg_info->mail_op);
1613 g_slice_free (GetMsgInfo, msg_info);
1618 update_account_notify_user_and_free (UpdateAccountInfo *info,
1619 TnyList *new_headers)
1621 /* Set the account back to not busy */
1622 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1623 info->account_name, FALSE);
1627 info->callback (info->mail_op, new_headers, info->user_data);
1629 /* Mail operation end */
1630 modest_mail_operation_notify_end (info->mail_op);
1634 g_object_unref (new_headers);
1635 destroy_update_account_info (info);
1639 inbox_refreshed_cb (TnyFolder *inbox,
1644 UpdateAccountInfo *info;
1645 ModestMailOperationPrivate *priv;
1646 TnyIterator *new_headers_iter;
1647 GPtrArray *new_headers_array = NULL;
1648 gint max_size, retrieve_limit, i;
1649 ModestAccountMgr *mgr;
1650 ModestAccountRetrieveType retrieve_type;
1651 TnyList *new_headers = NULL;
1652 gboolean headers_only;
1653 time_t time_to_store;
1655 info = (UpdateAccountInfo *) user_data;
1656 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1657 mgr = modest_runtime_get_account_mgr ();
1659 if (canceled || err) {
1660 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1662 priv->error = g_error_copy (err);
1664 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1665 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1669 tny_folder_remove_observer (inbox, info->inbox_observer);
1670 g_object_unref (info->inbox_observer);
1671 info->inbox_observer = NULL;
1673 /* Notify the user about the error and then exit */
1674 update_account_notify_user_and_free (info, NULL);
1679 /* Try to send anyway */
1683 /* Set the last updated as the current time */
1684 #ifdef MODEST_USE_LIBTIME
1686 time_get_utc (&utc_tm);
1687 time_to_store = time_mktime (&utc_tm, "GMT");
1689 time_to_store = time (NULL);
1691 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
1693 /* Get the message max size */
1694 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1695 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1697 max_size = G_MAXINT;
1699 max_size = max_size * KB;
1701 /* Create the new headers array. We need it to sort the
1702 new headers by date */
1703 new_headers_array = g_ptr_array_new ();
1704 if (info->inbox_observer) {
1705 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1706 while (!tny_iterator_is_done (new_headers_iter)) {
1707 TnyHeader *header = NULL;
1709 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1710 /* Apply per-message size limits */
1711 if (tny_header_get_message_size (header) < max_size)
1712 g_ptr_array_add (new_headers_array, g_object_ref (header));
1714 g_object_unref (header);
1715 tny_iterator_next (new_headers_iter);
1717 g_object_unref (new_headers_iter);
1719 tny_folder_remove_observer (inbox, info->inbox_observer);
1720 g_object_unref (info->inbox_observer);
1721 info->inbox_observer = NULL;
1724 if (new_headers_array->len == 0) {
1725 g_ptr_array_free (new_headers_array, FALSE);
1729 /* Get per-account message amount retrieval limit */
1730 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1731 if (retrieve_limit == 0)
1732 retrieve_limit = G_MAXINT;
1734 /* Get per-account retrieval type */
1735 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1736 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1739 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1741 /* Copy the headers to a list and free the array */
1742 new_headers = tny_simple_list_new ();
1743 for (i=0; i < new_headers_array->len; i++) {
1744 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1745 /* We want the first element to be the most recent
1746 one, that's why we reverse the list */
1747 tny_list_prepend (new_headers, G_OBJECT (header));
1749 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1750 g_ptr_array_free (new_headers_array, FALSE);
1752 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1755 GetMsgInfo *msg_info;
1758 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1760 iter = tny_list_create_iterator (new_headers);
1762 /* Create the message info */
1763 msg_info = g_slice_new0 (GetMsgInfo);
1764 msg_info->mail_op = g_object_ref (info->mail_op);
1765 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1766 msg_info->more_msgs = g_object_ref (iter);
1767 msg_info->msg = NULL;
1768 msg_info->user_data = info;
1770 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1771 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1772 TnyFolder *folder = tny_header_get_folder (header);
1774 /* Get message in an async way */
1775 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1778 g_object_unref (folder);
1779 g_object_unref (header);
1782 tny_iterator_next (iter);
1784 g_object_unref (iter);
1785 g_object_unref (new_headers);
1787 /* The mail operation will finish when the last
1788 message is retrieved */
1792 /* If we don't have to retrieve the new messages then
1794 update_account_send_mail (info);
1796 /* Check if the operation was a success */
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1800 /* Call the user callback and free */
1801 update_account_notify_user_and_free (info, new_headers);
1805 inbox_refresh_status_update (GObject *obj,
1809 UpdateAccountInfo *info = NULL;
1810 ModestMailOperation *self = NULL;
1811 ModestMailOperationPrivate *priv = NULL;
1812 ModestMailOperationState *state;
1814 g_return_if_fail (user_data != NULL);
1815 g_return_if_fail (status != NULL);
1817 /* Show only the status information we want */
1818 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1821 info = (UpdateAccountInfo *) user_data;
1822 self = info->mail_op;
1823 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1827 priv->done = status->position;
1828 priv->total = status->of_total;
1830 state = modest_mail_operation_clone_state (self);
1832 /* This is not a GDK lock because we are a Tinymail callback and
1833 * Tinymail already acquires the Gdk lock */
1834 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1836 g_slice_free (ModestMailOperationState, state);
1840 recurse_folders_async_cb (TnyFolderStore *folder_store,
1846 UpdateAccountInfo *info;
1847 ModestMailOperationPrivate *priv;
1849 info = (UpdateAccountInfo *) user_data;
1850 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1852 if (err || canceled) {
1853 /* If the error was previosly set by another callback
1854 don't set it again */
1856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1858 priv->error = g_error_copy (err);
1860 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1861 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1865 /* We're not getting INBOX children if we don't want to poke all */
1866 TnyIterator *iter = tny_list_create_iterator (list);
1867 while (!tny_iterator_is_done (iter)) {
1868 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1870 /* Add to the list of all folders */
1871 tny_list_append (info->folders, (GObject *) folder);
1873 if (info->poke_all) {
1874 TnyList *folders = tny_simple_list_new ();
1875 /* Add pending call */
1876 info->pending_calls++;
1878 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1879 recurse_folders_async_cb,
1881 g_object_unref (folders);
1884 g_object_unref (G_OBJECT (folder));
1886 tny_iterator_next (iter);
1888 g_object_unref (G_OBJECT (iter));
1891 /* Remove my own pending call */
1892 info->pending_calls--;
1894 /* This means that we have all the folders */
1895 if (info->pending_calls == 0) {
1896 TnyIterator *iter_all_folders;
1897 TnyFolder *inbox = NULL;
1899 /* If there was any error do not continue */
1901 update_account_notify_user_and_free (info, NULL);
1905 iter_all_folders = tny_list_create_iterator (info->folders);
1907 /* Do a poke status over all folders */
1908 while (!tny_iterator_is_done (iter_all_folders) &&
1909 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1910 TnyFolder *folder = NULL;
1912 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1914 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1915 /* Get a reference to the INBOX */
1916 inbox = g_object_ref (folder);
1918 /* Issue a poke status over the folder */
1920 tny_folder_poke_status (folder);
1923 /* Free and go to next */
1924 g_object_unref (folder);
1925 tny_iterator_next (iter_all_folders);
1927 g_object_unref (iter_all_folders);
1929 /* Refresh the INBOX */
1931 /* Refresh the folder. Our observer receives
1932 * the new emails during folder refreshes, so
1933 * we can use observer->new_headers
1935 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1936 tny_folder_add_observer (inbox, info->inbox_observer);
1938 /* Refresh the INBOX */
1939 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1940 g_object_unref (inbox);
1942 /* We could not perform the inbox refresh but
1943 we'll try to send mails anyway */
1944 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1950 modest_mail_operation_update_account (ModestMailOperation *self,
1951 const gchar *account_name,
1953 gboolean interactive,
1954 UpdateAccountCallback callback,
1957 UpdateAccountInfo *info = NULL;
1958 ModestMailOperationPrivate *priv = NULL;
1959 ModestTnyAccountStore *account_store = NULL;
1961 ModestMailOperationState *state;
1963 /* Init mail operation */
1964 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1967 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1968 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1970 /* Get the store account */
1971 account_store = modest_runtime_get_account_store ();
1973 modest_tny_account_store_get_server_account (account_store,
1975 TNY_ACCOUNT_TYPE_STORE);
1977 /* The above function could return NULL */
1978 if (!priv->account) {
1979 /* Check if the operation was a success */
1980 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1981 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1985 /* Call the user callback */
1987 callback (self, NULL, user_data);
1989 /* Notify about operation end */
1990 modest_mail_operation_notify_end (self);
1995 /* We have once seen priv->account getting finalized during this code,
1996 * therefore adding a reference (bug #82296) */
1998 g_object_ref (priv->account);
2000 /* Create the helper object */
2001 info = g_slice_new0 (UpdateAccountInfo);
2002 info->pending_calls = 1;
2003 info->folders = tny_simple_list_new ();
2004 info->mail_op = g_object_ref (self);
2005 info->poke_all = poke_all;
2006 info->interactive = interactive;
2007 info->account_name = g_strdup (account_name);
2008 info->callback = callback;
2009 info->user_data = user_data;
2011 /* Set account busy */
2012 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2013 modest_mail_operation_notify_start (self);
2015 /* notify about the start of the operation */
2016 state = modest_mail_operation_clone_state (self);
2020 /* Start notifying progress */
2021 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2022 g_slice_free (ModestMailOperationState, state);
2024 /* Get all folders and continue in the callback */
2025 folders = tny_simple_list_new ();
2026 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2027 folders, NULL, TRUE,
2028 recurse_folders_async_cb,
2030 g_object_unref (folders);
2032 g_object_unref (priv->account);
2037 * Used to notify the queue from the main
2038 * loop. We call it inside an idle call to achieve that
2041 idle_notify_queue (gpointer data)
2043 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2045 gdk_threads_enter ();
2046 modest_mail_operation_notify_end (mail_op);
2047 gdk_threads_leave ();
2048 g_object_unref (mail_op);
2054 compare_headers_by_date (gconstpointer a,
2057 TnyHeader **header1, **header2;
2058 time_t sent1, sent2;
2060 header1 = (TnyHeader **) a;
2061 header2 = (TnyHeader **) b;
2063 sent1 = tny_header_get_date_sent (*header1);
2064 sent2 = tny_header_get_date_sent (*header2);
2066 /* We want the most recent ones (greater time_t) at the
2075 /* ******************************************************************* */
2076 /* ************************** STORE ACTIONS ************************* */
2077 /* ******************************************************************* */
2080 ModestMailOperation *mail_op;
2081 CreateFolderUserCallback callback;
2087 create_folder_cb (TnyFolderStore *parent_folder,
2089 TnyFolder *new_folder,
2093 ModestMailOperationPrivate *priv;
2094 CreateFolderInfo *info;
2096 info = (CreateFolderInfo *) user_data;
2097 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2099 if (canceled || err) {
2100 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2102 priv->error = g_error_copy (err);
2104 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2105 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2108 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2111 /* The user will unref the new_folder */
2113 info->callback (info->mail_op, parent_folder,
2114 new_folder, info->user_data);
2116 /* Notify about operation end */
2117 modest_mail_operation_notify_end (info->mail_op);
2120 g_object_unref (info->mail_op);
2121 g_slice_free (CreateFolderInfo, info);
2125 modest_mail_operation_create_folder (ModestMailOperation *self,
2126 TnyFolderStore *parent,
2128 CreateFolderUserCallback callback,
2131 ModestMailOperationPrivate *priv;
2133 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2134 g_return_if_fail (name);
2136 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2137 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2138 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2139 g_object_ref (parent) :
2140 modest_tny_folder_get_account (TNY_FOLDER (parent));
2142 /* Check for already existing folder */
2143 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2144 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2145 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2146 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2147 _CS("ckdg_ib_folder_already_exists"));
2151 if (TNY_IS_FOLDER (parent)) {
2152 /* Check folder rules */
2153 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2154 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2155 /* Set status failed and set an error */
2156 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2157 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2158 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2159 _("mail_in_ui_folder_create_error"));
2163 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2164 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2165 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2166 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2167 _("mail_in_ui_folder_create_error"));
2171 CreateFolderInfo *info;
2173 info = g_slice_new0 (CreateFolderInfo);
2174 info->mail_op = g_object_ref (self);
2175 info->callback = callback;
2176 info->user_data = user_data;
2178 modest_mail_operation_notify_start (self);
2180 /* Create the folder */
2181 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2184 /* Call the user callback anyway */
2186 callback (self, parent, NULL, user_data);
2187 /* Notify about operation end */
2188 modest_mail_operation_notify_end (self);
2193 modest_mail_operation_remove_folder (ModestMailOperation *self,
2195 gboolean remove_to_trash)
2197 ModestMailOperationPrivate *priv;
2198 ModestTnyFolderRules rules;
2200 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2201 g_return_if_fail (TNY_IS_FOLDER (folder));
2203 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2205 /* Check folder rules */
2206 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2207 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2208 /* Set status failed and set an error */
2209 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2210 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2211 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2212 _("mail_in_ui_folder_delete_error"));
2216 /* Get the account */
2217 priv->account = modest_tny_folder_get_account (folder);
2218 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2220 /* Delete folder or move to trash */
2221 if (remove_to_trash) {
2222 TnyFolder *trash_folder = NULL;
2223 trash_folder = modest_tny_account_get_special_folder (priv->account,
2224 TNY_FOLDER_TYPE_TRASH);
2225 /* TODO: error_handling */
2227 modest_mail_operation_notify_start (self);
2228 modest_mail_operation_xfer_folder (self, folder,
2229 TNY_FOLDER_STORE (trash_folder),
2231 g_object_unref (trash_folder);
2233 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2236 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2238 modest_mail_operation_notify_start (self);
2239 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2240 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2243 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2245 g_object_unref (parent);
2247 g_warning ("%s: could not get parent folder", __FUNCTION__);
2251 /* Notify about operation end */
2252 modest_mail_operation_notify_end (self);
2256 transfer_folder_status_cb (GObject *obj,
2260 ModestMailOperation *self;
2261 ModestMailOperationPrivate *priv;
2262 ModestMailOperationState *state;
2263 XFerFolderAsyncHelper *helper;
2265 g_return_if_fail (status != NULL);
2267 /* Show only the status information we want */
2268 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2271 helper = (XFerFolderAsyncHelper *) user_data;
2272 g_return_if_fail (helper != NULL);
2274 self = helper->mail_op;
2275 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2277 priv->done = status->position;
2278 priv->total = status->of_total;
2280 state = modest_mail_operation_clone_state (self);
2282 /* This is not a GDK lock because we are a Tinymail callback
2283 * which is already GDK locked by Tinymail */
2285 /* no gdk_threads_enter (), CHECKED */
2287 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2289 /* no gdk_threads_leave (), CHECKED */
2291 g_slice_free (ModestMailOperationState, state);
2295 transfer_folder_cb (TnyFolder *folder,
2297 TnyFolderStore *into,
2298 TnyFolder *new_folder,
2302 XFerFolderAsyncHelper *helper;
2303 ModestMailOperation *self = NULL;
2304 ModestMailOperationPrivate *priv = NULL;
2306 helper = (XFerFolderAsyncHelper *) user_data;
2307 g_return_if_fail (helper != NULL);
2309 self = helper->mail_op;
2310 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2313 priv->error = g_error_copy (err);
2315 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2316 } else if (cancelled) {
2317 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2318 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2319 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2320 _("Transference of %s was cancelled."),
2321 tny_folder_get_name (folder));
2324 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2327 /* Update state of new folder */
2329 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2330 tny_folder_poke_status (new_folder);
2333 /* Notify about operation end */
2334 modest_mail_operation_notify_end (self);
2336 /* If user defined callback function was defined, call it */
2337 if (helper->user_callback) {
2339 /* This is not a GDK lock because we are a Tinymail callback
2340 * which is already GDK locked by Tinymail */
2342 /* no gdk_threads_enter (), CHECKED */
2343 helper->user_callback (self, new_folder, helper->user_data);
2344 /* no gdk_threads_leave () , CHECKED */
2348 g_object_unref (helper->mail_op);
2349 g_slice_free (XFerFolderAsyncHelper, helper);
2354 * This function checks if the new name is a valid name for our local
2355 * folders account. The new name could not be the same than then name
2356 * of any of the mandatory local folders
2358 * We can not rely on tinymail because tinymail does not check the
2359 * name of the virtual folders that the account could have in the case
2360 * that we're doing a rename (because it directly calls Camel which
2361 * knows nothing about our virtual folders).
2363 * In the case of an actual copy/move (i.e. move/copy a folder between
2364 * accounts) tinymail uses the tny_folder_store_create_account which
2365 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2366 * checks the new name of the folder, so this call in that case
2367 * wouldn't be needed. *But* NOTE that if tinymail changes its
2368 * implementation (if folder transfers within the same account is no
2369 * longer implemented as a rename) this call will allow Modest to work
2372 * If the new name is not valid, this function will set the status to
2373 * failed and will set also an error in the mail operation
2376 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2377 TnyFolderStore *into,
2378 const gchar *new_name)
2380 if (TNY_IS_ACCOUNT (into) &&
2381 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2382 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2384 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2385 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2386 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2387 _CS("ckdg_ib_folder_already_exists"));
2394 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2396 TnyFolderStore *parent,
2397 gboolean delete_original,
2398 XferFolderAsyncUserCallback user_callback,
2401 ModestMailOperationPrivate *priv = NULL;
2402 ModestTnyFolderRules parent_rules = 0, rules;
2403 XFerFolderAsyncHelper *helper = NULL;
2404 const gchar *folder_name = NULL;
2405 const gchar *error_msg;
2407 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2408 g_return_if_fail (TNY_IS_FOLDER (folder));
2409 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2412 folder_name = tny_folder_get_name (folder);
2414 /* Set the error msg */
2415 error_msg = _("mail_in_ui_folder_move_target_error");
2417 /* Get account and set it into mail_operation */
2418 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2419 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2420 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2422 /* Get folder rules */
2423 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2424 if (TNY_IS_FOLDER (parent))
2425 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2427 /* Apply operation constraints */
2428 if ((gpointer) parent == (gpointer) folder ||
2429 (!TNY_IS_FOLDER_STORE (parent)) ||
2430 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2433 } else if (TNY_IS_FOLDER (parent) &&
2434 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2438 } else if (TNY_IS_FOLDER (parent) &&
2439 TNY_IS_FOLDER_STORE (folder) &&
2440 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2441 TNY_FOLDER_STORE (folder))) {
2442 /* Do not move a parent into a child */
2444 } else if (TNY_IS_FOLDER_STORE (parent) &&
2445 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2446 /* Check that the new folder name is not used by any
2449 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2450 /* Check that the new folder name is not used by any
2451 special local folder */
2454 /* Create the helper */
2455 helper = g_slice_new0 (XFerFolderAsyncHelper);
2456 helper->mail_op = g_object_ref (self);
2457 helper->user_callback = user_callback;
2458 helper->user_data = user_data;
2460 /* Move/Copy folder */
2461 modest_mail_operation_notify_start (self);
2462 tny_folder_copy_async (folder,
2464 tny_folder_get_name (folder),
2467 transfer_folder_status_cb,
2473 /* Set status failed and set an error */
2474 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2475 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2476 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2479 /* Call the user callback if exists */
2481 user_callback (self, NULL, user_data);
2483 /* Notify the queue */
2484 modest_mail_operation_notify_end (self);
2488 modest_mail_operation_rename_folder (ModestMailOperation *self,
2491 XferFolderAsyncUserCallback user_callback,
2494 ModestMailOperationPrivate *priv;
2495 ModestTnyFolderRules rules;
2496 XFerFolderAsyncHelper *helper;
2498 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2499 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2500 g_return_if_fail (name);
2502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2504 /* Get account and set it into mail_operation */
2505 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2506 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2508 /* Check folder rules */
2509 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2510 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2512 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2515 TnyFolderStore *into;
2517 into = tny_folder_get_folder_store (folder);
2519 /* Check that the new folder name is not used by any
2520 special local folder */
2521 if (new_name_valid_if_local_account (priv, into, name)) {
2522 /* Create the helper */
2523 helper = g_slice_new0 (XFerFolderAsyncHelper);
2524 helper->mail_op = g_object_ref(self);
2525 helper->user_callback = user_callback;
2526 helper->user_data = user_data;
2528 /* Rename. Camel handles folder subscription/unsubscription */
2529 modest_mail_operation_notify_start (self);
2530 tny_folder_copy_async (folder, into, name, TRUE,
2532 transfer_folder_status_cb,
2534 g_object_unref (into);
2536 g_object_unref (into);
2543 /* Set status failed and set an error */
2544 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2545 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2546 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2547 _("FIXME: unable to rename"));
2550 user_callback (self, NULL, user_data);
2552 /* Notify about operation end */
2553 modest_mail_operation_notify_end (self);
2556 /* ******************************************************************* */
2557 /* ************************** MSG ACTIONS ************************* */
2558 /* ******************************************************************* */
2561 modest_mail_operation_find_msg (ModestMailOperation *self,
2563 const gchar *msg_uid,
2564 gboolean progress_feedback,
2565 GetMsgAsyncUserCallback user_callback,
2568 GetMsgInfo *helper = NULL;
2569 ModestMailOperationPrivate *priv;
2571 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2572 g_return_if_fail (msg_uid != NULL);
2574 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2575 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2579 /* Check memory low */
2580 if (_check_memory_low (self)) {
2582 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2583 modest_mail_operation_notify_end (self);
2587 /* Get account and set it into mail_operation */
2588 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2590 /* Check for cached messages */
2591 if (progress_feedback) {
2592 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2594 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2597 /* Create the helper */
2598 helper = g_slice_new0 (GetMsgInfo);
2599 helper->header = NULL;
2600 helper->mail_op = g_object_ref (self);
2601 helper->user_callback = user_callback;
2602 helper->user_data = user_data;
2603 helper->destroy_notify = NULL;
2604 helper->last_total_bytes = 0;
2605 helper->sum_total_bytes = 0;
2606 helper->total_bytes = 0;
2607 helper->more_msgs = NULL;
2608 helper->get_parts = NULL;
2611 modest_mail_operation_notify_start (self);
2613 /* notify about the start of the operation */
2614 ModestMailOperationState *state;
2615 state = modest_mail_operation_clone_state (self);
2618 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2620 g_slice_free (ModestMailOperationState, state);
2622 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2626 modest_mail_operation_get_msg (ModestMailOperation *self,
2628 gboolean progress_feedback,
2629 GetMsgAsyncUserCallback user_callback,
2632 GetMsgInfo *helper = NULL;
2634 ModestMailOperationPrivate *priv;
2636 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2637 g_return_if_fail (TNY_IS_HEADER (header));
2639 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2640 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2644 /* Check memory low */
2645 if (_check_memory_low (self)) {
2647 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2648 modest_mail_operation_notify_end (self);
2652 /* Get account and set it into mail_operation */
2653 folder = tny_header_get_folder (header);
2654 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2656 /* Check for cached messages */
2657 if (progress_feedback) {
2658 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2659 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2661 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2663 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2666 /* Create the helper */
2667 helper = g_slice_new0 (GetMsgInfo);
2668 helper->header = g_object_ref (header);
2669 helper->mail_op = g_object_ref (self);
2670 helper->user_callback = user_callback;
2671 helper->user_data = user_data;
2672 helper->destroy_notify = NULL;
2673 helper->last_total_bytes = 0;
2674 helper->sum_total_bytes = 0;
2675 helper->total_bytes = tny_header_get_message_size (header);
2676 helper->more_msgs = NULL;
2677 helper->get_parts = NULL;
2680 modest_mail_operation_notify_start (self);
2682 /* notify about the start of the operation */
2683 ModestMailOperationState *state;
2684 state = modest_mail_operation_clone_state (self);
2687 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2689 g_slice_free (ModestMailOperationState, state);
2691 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2693 g_object_unref (G_OBJECT (folder));
2697 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2700 gboolean progress_feedback,
2701 GetMsgAsyncUserCallback user_callback,
2704 GetMsgInfo *helper = NULL;
2706 ModestMailOperationPrivate *priv;
2708 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2709 g_return_if_fail (TNY_IS_HEADER (header));
2711 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2712 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2716 /* Check memory low */
2717 if (_check_memory_low (self)) {
2719 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2720 modest_mail_operation_notify_end (self);
2724 /* Get account and set it into mail_operation */
2725 folder = tny_header_get_folder (header);
2726 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2728 /* Check for cached messages */
2729 if (progress_feedback) {
2730 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2731 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2733 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2735 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2738 /* Create the helper */
2739 helper = g_slice_new0 (GetMsgInfo);
2740 helper->header = g_object_ref (header);
2741 helper->mail_op = g_object_ref (self);
2742 helper->user_callback = user_callback;
2743 helper->user_data = user_data;
2744 helper->destroy_notify = NULL;
2745 helper->last_total_bytes = 0;
2746 helper->sum_total_bytes = 0;
2747 helper->total_bytes = tny_header_get_message_size (header);
2748 helper->more_msgs = NULL;
2749 helper->get_parts = tny_list_create_iterator (parts);
2752 modest_mail_operation_notify_start (self);
2754 /* notify about the start of the operation */
2755 ModestMailOperationState *state;
2756 state = modest_mail_operation_clone_state (self);
2759 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2761 g_slice_free (ModestMailOperationState, state);
2763 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2765 g_object_unref (G_OBJECT (folder));
2769 get_msg_status_cb (GObject *obj,
2773 GetMsgInfo *helper = NULL;
2775 g_return_if_fail (status != NULL);
2777 /* Show only the status information we want */
2778 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2781 helper = (GetMsgInfo *) user_data;
2782 g_return_if_fail (helper != NULL);
2784 /* Notify progress */
2785 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2786 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2790 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2793 TnyFolder *folder = NULL;
2795 helper = (GetMsgInfo *) user_data;
2797 if (helper->header) {
2798 folder = tny_header_get_folder (helper->header);
2801 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2803 if (folder) g_object_unref (folder);
2807 get_msg_async_cb (TnyFolder *folder,
2813 GetMsgInfo *info = NULL;
2814 ModestMailOperationPrivate *priv = NULL;
2817 info = (GetMsgInfo *) user_data;
2819 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2822 if (info->more_msgs) {
2823 tny_iterator_next (info->more_msgs);
2824 finished = (tny_iterator_is_done (info->more_msgs));
2825 } else if (info->get_parts) {
2826 tny_iterator_next (info->get_parts);
2827 finished = (tny_iterator_is_done (info->get_parts));
2829 finished = (priv->done == priv->total) ? TRUE : FALSE;
2832 /* If canceled by the user, ignore the error given by Tinymail */
2836 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2838 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2839 priv->error = g_error_copy ((const GError *) err);
2841 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2843 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2844 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2845 "%s", err->message);
2847 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2848 /* Set the success status before calling the user callback */
2849 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2852 if (info->header == NULL && msg)
2853 info->header = tny_msg_get_header (msg);
2855 /* Call the user callback */
2856 if (info->user_callback && (finished || (info->get_parts == NULL)))
2857 info->user_callback (info->mail_op, info->header, canceled,
2858 msg, err, info->user_data);
2860 /* Notify about operation end if this is the last callback */
2862 /* Free user data */
2863 if (info->destroy_notify)
2864 info->destroy_notify (info->user_data);
2866 /* Notify about operation end */
2867 modest_mail_operation_notify_end (info->mail_op);
2871 g_object_unref (info->msg);
2872 if (info->more_msgs)
2873 g_object_unref (info->more_msgs);
2875 g_object_unref (info->header);
2876 g_object_unref (info->mail_op);
2877 g_slice_free (GetMsgInfo, info);
2878 } else if (info->get_parts) {
2879 CamelStream *null_stream;
2880 TnyStream *tny_null_stream;
2883 if (info->msg == NULL && msg != NULL)
2884 info->msg = g_object_ref (msg);
2886 null_stream = camel_stream_null_new ();
2887 tny_null_stream = tny_camel_stream_new (null_stream);
2889 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
2890 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
2891 get_msg_async_get_part_cb,
2894 g_object_unref (tny_null_stream);
2895 g_object_unref (part);
2897 } else if (info->more_msgs) {
2898 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2899 TnyFolder *folder = tny_header_get_folder (header);
2901 g_object_unref (info->header);
2902 info->header = g_object_ref (header);
2904 /* Retrieve the next message */
2905 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2907 g_object_unref (header);
2908 g_object_unref (folder);
2910 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2915 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2916 TnyList *header_list,
2917 GetMsgAsyncUserCallback user_callback,
2919 GDestroyNotify notify)
2921 ModestMailOperationPrivate *priv = NULL;
2923 TnyIterator *iter = NULL;
2924 gboolean has_uncached_messages;
2926 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2928 /* Init mail operation */
2929 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2930 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2932 priv->total = tny_list_get_length(header_list);
2934 /* Check memory low */
2935 if (_check_memory_low (self)) {
2936 if (user_callback) {
2937 TnyHeader *header = NULL;
2940 if (tny_list_get_length (header_list) > 0) {
2941 iter = tny_list_create_iterator (header_list);
2942 header = (TnyHeader *) tny_iterator_get_current (iter);
2943 g_object_unref (iter);
2945 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2947 g_object_unref (header);
2951 /* Notify about operation end */
2952 modest_mail_operation_notify_end (self);
2956 /* Check uncached messages */
2957 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2958 !has_uncached_messages && !tny_iterator_is_done (iter);
2959 tny_iterator_next (iter)) {
2962 header = (TnyHeader *) tny_iterator_get_current (iter);
2963 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2964 has_uncached_messages = TRUE;
2965 g_object_unref (header);
2967 g_object_unref (iter);
2968 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2970 /* Get account and set it into mail_operation */
2971 if (tny_list_get_length (header_list) >= 1) {
2972 TnyIterator *iterator = tny_list_create_iterator (header_list);
2973 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2975 TnyFolder *folder = tny_header_get_folder (header);
2977 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2978 g_object_unref (folder);
2980 g_object_unref (header);
2982 g_object_unref (iterator);
2985 msg_list_size = compute_message_list_size (header_list, 0);
2987 modest_mail_operation_notify_start (self);
2988 iter = tny_list_create_iterator (header_list);
2989 if (!tny_iterator_is_done (iter)) {
2990 /* notify about the start of the operation */
2991 ModestMailOperationState *state;
2992 state = modest_mail_operation_clone_state (self);
2995 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2998 GetMsgInfo *msg_info = NULL;
2999 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3000 TnyFolder *folder = tny_header_get_folder (header);
3002 /* Create the message info */
3003 msg_info = g_slice_new0 (GetMsgInfo);
3004 msg_info->mail_op = g_object_ref (self);
3005 msg_info->header = g_object_ref (header);
3006 msg_info->more_msgs = g_object_ref (iter);
3007 msg_info->user_callback = user_callback;
3008 msg_info->user_data = user_data;
3009 msg_info->destroy_notify = notify;
3010 msg_info->last_total_bytes = 0;
3011 msg_info->sum_total_bytes = 0;
3012 msg_info->total_bytes = msg_list_size;
3013 msg_info->msg = NULL;
3015 /* The callback will call it per each header */
3016 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3018 /* Free and go on */
3019 g_object_unref (header);
3020 g_object_unref (folder);
3021 g_slice_free (ModestMailOperationState, state);
3023 g_object_unref (iter);
3028 remove_msgs_async_cb (TnyFolder *folder,
3034 const gchar *account_name;
3035 TnyAccount *account;
3036 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3037 ModestMailOperation *self;
3038 ModestMailOperationPrivate *priv;
3039 ModestProtocolRegistry *protocol_registry;
3040 SyncFolderHelper *helper;
3042 self = (ModestMailOperation *) user_data;
3043 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3044 protocol_registry = modest_runtime_get_protocol_registry ();
3046 if (canceled || err) {
3047 /* If canceled by the user, ignore the error given by Tinymail */
3049 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3051 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3052 priv->error = g_error_copy ((const GError *) err);
3053 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3056 modest_mail_operation_notify_end (self);
3057 g_object_unref (self);
3061 account = modest_tny_folder_get_account (folder);
3062 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3063 account_proto = modest_tny_account_get_protocol_type (account);
3064 g_object_unref (account);
3066 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3067 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3077 helper = g_slice_new0 (SyncFolderHelper);
3078 helper->mail_op = g_object_ref (self);
3079 helper->user_callback = NULL;
3080 helper->user_data = NULL;
3083 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3085 /* Remove the extra reference */
3086 g_object_unref (self);
3090 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3092 gboolean remove_to_trash /*ignored*/)
3094 TnyFolder *folder = NULL;
3095 ModestMailOperationPrivate *priv;
3096 TnyIterator *iter = NULL;
3097 TnyHeader *header = NULL;
3098 TnyList *remove_headers = NULL;
3099 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3100 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3102 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3103 g_return_if_fail (TNY_IS_LIST (headers));
3105 if (remove_to_trash)
3106 g_warning ("remove to trash is not implemented");
3108 if (tny_list_get_length(headers) == 0) {
3109 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3110 goto cleanup; /* nothing to do */
3113 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3115 /* Get folder from first header and sync it */
3116 iter = tny_list_create_iterator (headers);
3117 header = TNY_HEADER (tny_iterator_get_current (iter));
3118 g_object_unref (iter);
3120 folder = tny_header_get_folder (header);
3121 if (!TNY_IS_FOLDER(folder)) {
3122 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3126 /* Use the merged folder if we're removing messages from outbox */
3127 if (modest_tny_folder_is_local_folder (folder)) {
3128 ModestTnyLocalFoldersAccount *local_account;
3130 local_account = (ModestTnyLocalFoldersAccount *)
3131 modest_tny_account_store_get_local_folders_account (accstore);
3132 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3133 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3134 g_object_unref (folder);
3135 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3137 g_object_unref (local_account);
3140 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3141 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3143 while (!tny_iterator_is_done (headers_iter)) {
3144 TnyTransportAccount *traccount = NULL;
3145 TnyHeader *hdr = NULL;
3147 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3148 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3151 ModestTnySendQueueStatus status;
3152 ModestTnySendQueue *send_queue;
3154 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3155 if (TNY_IS_SEND_QUEUE (send_queue)) {
3158 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3159 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3160 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3161 if (G_UNLIKELY (remove_headers == NULL))
3162 remove_headers = tny_simple_list_new ();
3163 tny_list_append(remove_headers, G_OBJECT(hdr));
3167 g_object_unref(traccount);
3169 g_object_unref(hdr);
3170 tny_iterator_next (headers_iter);
3172 g_object_unref(headers_iter);
3175 /* Get account and set it into mail_operation */
3176 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3177 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3178 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3180 if (!remove_headers)
3181 remove_headers = g_object_ref (headers);
3183 /* remove message from folder */
3184 modest_mail_operation_notify_start (self);
3185 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3186 NULL, g_object_ref (self));
3190 g_object_unref (remove_headers);
3192 g_object_unref (header);
3194 g_object_unref (folder);
3198 notify_progress_of_multiple_messages (ModestMailOperation *self,
3200 gint *last_total_bytes,
3201 gint *sum_total_bytes,
3203 gboolean increment_done)
3205 ModestMailOperationPrivate *priv;
3206 ModestMailOperationState *state;
3207 gboolean is_num_bytes = FALSE;
3209 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3211 /* We know that tinymail sends us information about
3212 * transferred bytes with this particular message
3214 if (status->message)
3215 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3217 state = modest_mail_operation_clone_state (self);
3218 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3219 /* We know that we're in a different message when the
3220 total number of bytes to transfer is different. Of
3221 course it could fail if we're transferring messages
3222 of the same size, but this is a workarround */
3223 if (status->of_total != *last_total_bytes) {
3224 /* We need to increment the done when there is
3225 no information about each individual
3226 message, we need to do this in message
3227 transfers, and we don't do it for getting
3231 *sum_total_bytes += *last_total_bytes;
3232 *last_total_bytes = status->of_total;
3234 state->bytes_done += status->position + *sum_total_bytes;
3235 state->bytes_total = total_bytes;
3237 /* Notify the status change. Only notify about changes
3238 referred to bytes */
3239 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3243 g_slice_free (ModestMailOperationState, state);
3247 transfer_msgs_status_cb (GObject *obj,
3251 XFerMsgsAsyncHelper *helper;
3253 g_return_if_fail (status != NULL);
3255 /* Show only the status information we want */
3256 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3259 helper = (XFerMsgsAsyncHelper *) user_data;
3260 g_return_if_fail (helper != NULL);
3262 /* Notify progress */
3263 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3264 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3268 transfer_msgs_sync_folder_cb (TnyFolder *self,
3273 XFerMsgsAsyncHelper *helper;
3274 /* We don't care here about the results of the
3276 helper = (XFerMsgsAsyncHelper *) user_data;
3278 /* Notify about operation end */
3279 modest_mail_operation_notify_end (helper->mail_op);
3281 /* If user defined callback function was defined, call it */
3282 if (helper->user_callback)
3283 helper->user_callback (helper->mail_op, helper->user_data);
3286 if (helper->more_msgs)
3287 g_object_unref (helper->more_msgs);
3288 if (helper->headers)
3289 g_object_unref (helper->headers);
3290 if (helper->dest_folder)
3291 g_object_unref (helper->dest_folder);
3292 if (helper->mail_op)
3293 g_object_unref (helper->mail_op);
3294 g_slice_free (XFerMsgsAsyncHelper, helper);
3298 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3300 XFerMsgsAsyncHelper *helper;
3301 ModestMailOperation *self;
3302 ModestMailOperationPrivate *priv;
3303 gboolean finished = TRUE;
3305 helper = (XFerMsgsAsyncHelper *) user_data;
3306 self = helper->mail_op;
3308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3311 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3313 priv->error = g_error_copy (err);
3315 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3316 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3317 if (helper->more_msgs) {
3318 /* We'll transfer the next message in the list */
3319 tny_iterator_next (helper->more_msgs);
3320 if (!tny_iterator_is_done (helper->more_msgs)) {
3321 GObject *next_header;
3322 g_object_unref (helper->headers);
3323 helper->headers = tny_simple_list_new ();
3324 next_header = tny_iterator_get_current (helper->more_msgs);
3325 tny_list_append (helper->headers, next_header);
3326 g_object_unref (next_header);
3332 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3337 /* Synchronize the source folder contents. This should
3338 be done by tinymail but the camel_folder_sync it's
3339 actually disabled in transfer_msgs_thread_clean
3340 because it's supposed to cause hangs */
3341 tny_folder_sync_async (folder, helper->delete,
3342 transfer_msgs_sync_folder_cb,
3345 /* Transfer more messages */
3346 tny_folder_transfer_msgs_async (folder,
3348 helper->dest_folder,
3351 transfer_msgs_status_cb,
3356 /* Computes the size of the messages the headers in the list belongs
3357 to. If num_elements is different from 0 then it only takes into
3358 account the first num_elements for the calculation */
3360 compute_message_list_size (TnyList *headers,
3364 guint size = 0, element = 0;
3366 /* If num_elements is not valid then take all into account */
3367 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3368 num_elements = tny_list_get_length (headers);
3370 iter = tny_list_create_iterator (headers);
3371 while (!tny_iterator_is_done (iter) && element < num_elements) {
3372 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3373 size += tny_header_get_message_size (header);
3374 g_object_unref (header);
3375 tny_iterator_next (iter);
3378 g_object_unref (iter);
3384 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3387 gboolean delete_original,
3388 XferMsgsAsyncUserCallback user_callback,
3391 ModestMailOperationPrivate *priv = NULL;
3392 TnyIterator *iter = NULL;
3393 TnyFolder *src_folder = NULL;
3394 XFerMsgsAsyncHelper *helper = NULL;
3395 TnyHeader *header = NULL;
3396 ModestTnyFolderRules rules = 0;
3397 TnyAccount *dst_account = NULL;
3398 gboolean leave_on_server;
3399 ModestMailOperationState *state;
3400 ModestProtocolRegistry *protocol_registry;
3401 ModestProtocolType account_protocol;
3403 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3404 g_return_if_fail (headers && TNY_IS_LIST (headers));
3405 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3408 protocol_registry = modest_runtime_get_protocol_registry ();
3410 priv->total = tny_list_get_length (headers);
3412 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3413 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3415 /* Apply folder rules */
3416 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3417 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3418 /* Set status failed and set an error */
3419 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3420 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3421 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3422 _CS("ckct_ib_unable_to_paste_here"));
3423 /* Notify the queue */
3424 modest_mail_operation_notify_end (self);
3428 /* Get source folder */
3429 iter = tny_list_create_iterator (headers);
3430 header = TNY_HEADER (tny_iterator_get_current (iter));
3432 src_folder = tny_header_get_folder (header);
3433 g_object_unref (header);
3435 g_object_unref (iter);
3437 if (src_folder == NULL) {
3438 /* Notify the queue */
3439 modest_mail_operation_notify_end (self);
3441 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3446 /* Check folder source and destination */
3447 if (src_folder == folder) {
3448 /* Set status failed and set an error */
3449 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3450 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3451 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3452 _("mail_in_ui_folder_copy_target_error"));
3454 /* Notify the queue */
3455 modest_mail_operation_notify_end (self);
3458 g_object_unref (src_folder);
3462 /* Create the helper */
3463 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3464 helper->mail_op = g_object_ref(self);
3465 helper->dest_folder = g_object_ref(folder);
3466 helper->user_callback = user_callback;
3467 helper->user_data = user_data;
3468 helper->last_total_bytes = 0;
3469 helper->sum_total_bytes = 0;
3470 helper->total_bytes = compute_message_list_size (headers, 0);
3472 /* Get account and set it into mail_operation */
3473 priv->account = modest_tny_folder_get_account (src_folder);
3474 dst_account = modest_tny_folder_get_account (folder);
3476 if (priv->account == dst_account) {
3477 /* Transfer all messages at once using the fast
3478 * method. Note that depending on the server this
3479 * might not be that fast, and might not be
3480 * user-cancellable either */
3481 helper->headers = g_object_ref (headers);
3482 helper->more_msgs = NULL;
3484 /* Transfer messages one by one so the user can cancel
3487 helper->headers = tny_simple_list_new ();
3488 helper->more_msgs = tny_list_create_iterator (headers);
3489 hdr = tny_iterator_get_current (helper->more_msgs);
3490 tny_list_append (helper->headers, hdr);
3491 g_object_unref (hdr);
3494 /* If leave_on_server is set to TRUE then don't use
3495 delete_original, we always pass FALSE. This is because
3496 otherwise tinymail will try to sync the source folder and
3497 this could cause an error if we're offline while
3498 transferring an already downloaded message from a POP
3500 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3501 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3502 const gchar *account_name;
3504 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3505 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3508 leave_on_server = FALSE;
3511 /* Do not delete messages if leave on server is TRUE */
3512 helper->delete = (leave_on_server) ? FALSE : delete_original;
3514 modest_mail_operation_notify_start (self);
3516 /* Start notifying progress */
3517 state = modest_mail_operation_clone_state (self);
3520 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3521 g_slice_free (ModestMailOperationState, state);
3523 tny_folder_transfer_msgs_async (src_folder,
3528 transfer_msgs_status_cb,
3530 g_object_unref (src_folder);
3531 g_object_unref (dst_account);
3536 on_refresh_folder (TnyFolder *folder,
3541 RefreshAsyncHelper *helper = NULL;
3542 ModestMailOperation *self = NULL;
3543 ModestMailOperationPrivate *priv = NULL;
3545 helper = (RefreshAsyncHelper *) user_data;
3546 self = helper->mail_op;
3547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3549 g_return_if_fail(priv!=NULL);
3552 priv->error = g_error_copy (error);
3553 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3558 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3559 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3560 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3561 _("Error trying to refresh the contents of %s"),
3562 tny_folder_get_name (folder));
3566 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3569 /* Call user defined callback, if it exists */
3570 if (helper->user_callback) {
3572 /* This is not a GDK lock because we are a Tinymail callback and
3573 * Tinymail already acquires the Gdk lock */
3574 helper->user_callback (self, folder, helper->user_data);
3578 g_slice_free (RefreshAsyncHelper, helper);
3580 /* Notify about operation end */
3581 modest_mail_operation_notify_end (self);
3582 g_object_unref(self);
3586 on_refresh_folder_status_update (GObject *obj,
3590 RefreshAsyncHelper *helper = NULL;
3591 ModestMailOperation *self = NULL;
3592 ModestMailOperationPrivate *priv = NULL;
3593 ModestMailOperationState *state;
3595 g_return_if_fail (user_data != NULL);
3596 g_return_if_fail (status != NULL);
3598 /* Show only the status information we want */
3599 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3602 helper = (RefreshAsyncHelper *) user_data;
3603 self = helper->mail_op;
3604 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3606 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3608 priv->done = status->position;
3609 priv->total = status->of_total;
3611 state = modest_mail_operation_clone_state (self);
3613 /* This is not a GDK lock because we are a Tinymail callback and
3614 * Tinymail already acquires the Gdk lock */
3615 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3617 g_slice_free (ModestMailOperationState, state);
3621 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3623 RefreshAsyncUserCallback user_callback,
3626 ModestMailOperationPrivate *priv = NULL;
3627 RefreshAsyncHelper *helper = NULL;
3629 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3631 /* Check memory low */
3632 if (_check_memory_low (self)) {
3634 user_callback (self, folder, user_data);
3635 /* Notify about operation end */
3636 modest_mail_operation_notify_end (self);
3640 /* Get account and set it into mail_operation */
3641 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3642 priv->account = modest_tny_folder_get_account (folder);
3643 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3645 /* Create the helper */
3646 helper = g_slice_new0 (RefreshAsyncHelper);
3647 helper->mail_op = g_object_ref(self);
3648 helper->user_callback = user_callback;
3649 helper->user_data = user_data;
3651 modest_mail_operation_notify_start (self);
3653 /* notify that the operation was started */
3654 ModestMailOperationState *state;
3655 state = modest_mail_operation_clone_state (self);
3658 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3660 g_slice_free (ModestMailOperationState, state);
3662 tny_folder_refresh_async (folder,
3664 on_refresh_folder_status_update,
3669 run_queue_notify_and_destroy (RunQueueHelper *helper,
3670 ModestMailOperationStatus status)
3672 ModestMailOperationPrivate *priv;
3675 if (helper->error_handler &&
3676 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3677 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3678 if (helper->start_handler &&
3679 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3680 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3681 if (helper->stop_handler &&
3682 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3683 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3686 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3687 priv->status = status;
3690 modest_mail_operation_notify_end (helper->self);
3693 g_object_unref (helper->queue);
3694 g_object_unref (helper->self);
3695 g_slice_free (RunQueueHelper, helper);
3699 run_queue_stop (ModestTnySendQueue *queue,
3702 RunQueueHelper *helper;
3704 g_debug ("%s sending queue stopped", __FUNCTION__);
3706 helper = (RunQueueHelper *) user_data;
3707 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3711 modest_mail_operation_run_queue (ModestMailOperation *self,
3712 ModestTnySendQueue *queue)
3714 ModestMailOperationPrivate *priv;
3715 RunQueueHelper *helper;
3717 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3718 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3719 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3721 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3722 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3723 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3725 /* Create the helper */
3726 helper = g_slice_new0 (RunQueueHelper);
3727 helper->queue = g_object_ref (queue);
3728 helper->self = g_object_ref (self);
3729 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3730 G_CALLBACK (run_queue_stop),
3733 /* Notify operation has started */
3734 modest_mail_operation_notify_start (self);
3735 g_debug ("%s, run queue started", __FUNCTION__);
3739 queue_wakeup_callback (ModestTnySendQueue *queue,
3744 ModestMailOperation *mail_op;
3745 ModestMailOperationPrivate *priv;
3747 mail_op = (ModestMailOperation *) userdata;
3748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3750 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3751 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3754 modest_mail_operation_notify_end (mail_op);
3755 g_object_unref (mail_op);
3759 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3760 ModestTnySendQueue *queue)
3762 ModestMailOperationPrivate *priv;
3764 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3765 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3766 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3768 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3769 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3770 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3772 g_object_ref (self);
3774 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3775 modest_mail_operation_notify_start (self);
3779 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3781 ModestMailOperation *self = (ModestMailOperation *) userdata;
3782 ModestMailOperationPrivate *priv;
3784 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3785 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3786 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3788 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3790 modest_mail_operation_notify_end (self);
3791 g_object_unref (self);
3795 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3797 ModestMailOperationPrivate *priv;
3799 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3800 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3801 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3803 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3805 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3806 priv->account = NULL;
3807 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3809 modest_mail_operation_notify_start (self);
3810 g_object_ref (self);
3811 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3815 sync_folder_finish_callback (TnyFolder *self,
3821 ModestMailOperationPrivate *priv;
3822 SyncFolderHelper *helper;
3824 helper = (SyncFolderHelper *) user_data;
3825 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3827 /* If canceled by the user, ignore the error given by Tinymail */
3829 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3831 /* If the operation was a sync then the status is
3832 failed, but if it's part of another operation then
3833 just set it as finished with errors */
3834 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3835 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3837 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3838 priv->error = g_error_copy ((const GError *) err);
3839 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3841 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3845 if (helper->user_callback)
3846 helper->user_callback (helper->mail_op, self, helper->user_data);
3848 modest_mail_operation_notify_end (helper->mail_op);
3851 g_object_unref (helper->mail_op);
3852 g_slice_free (SyncFolderHelper, helper);
3856 modest_mail_operation_sync_folder (ModestMailOperation *self,
3859 SyncFolderCallback callback,
3862 ModestMailOperationPrivate *priv;
3863 SyncFolderHelper *helper;
3865 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3866 g_return_if_fail (TNY_IS_FOLDER (folder));
3867 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3869 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3870 priv->account = modest_tny_folder_get_account (folder);
3871 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3874 helper = g_slice_new0 (SyncFolderHelper);
3875 helper->mail_op = g_object_ref (self);
3876 helper->user_callback = callback;
3877 helper->user_data = user_data;
3879 modest_mail_operation_notify_start (self);
3880 tny_folder_sync_async (folder, expunge,
3881 (TnyFolderCallback) sync_folder_finish_callback,
3886 modest_mail_operation_notify_start (ModestMailOperation *self)
3888 ModestMailOperationPrivate *priv = NULL;
3890 g_return_if_fail (self);
3892 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3894 /* Ensure that all the fields are filled correctly */
3895 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3897 /* Notify the observers about the mail operation. We do not
3898 wrapp this emission because we assume that this function is
3899 always called from within the main lock */
3900 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3905 * It's used by the mail operation queue to notify the observers
3906 * attached to that signal that the operation finished. We need to use
3907 * that because tinymail does not give us the progress of a given
3908 * operation when it finishes (it directly calls the operation
3912 modest_mail_operation_notify_end (ModestMailOperation *self)
3914 ModestMailOperationPrivate *priv = NULL;
3916 g_return_if_fail (self);
3918 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3920 /* Notify the observers about the mail operation end. We do
3921 not wrapp this emission because we assume that this
3922 function is always called from within the main lock */
3923 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3925 /* Remove the error user data */
3926 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3927 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3931 modest_mail_operation_get_account (ModestMailOperation *self)
3933 ModestMailOperationPrivate *priv = NULL;
3935 g_return_val_if_fail (self, NULL);
3937 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3939 return (priv->account) ? g_object_ref (priv->account) : NULL;
3943 modest_mail_operation_noop (ModestMailOperation *self)
3945 ModestMailOperationPrivate *priv = NULL;
3947 g_return_if_fail (self);
3949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3950 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3951 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3955 /* This mail operation does nothing actually */
3956 modest_mail_operation_notify_start (self);
3957 modest_mail_operation_notify_end (self);
3962 modest_mail_operation_to_string (ModestMailOperation *self)
3964 const gchar *type, *status, *account_id;
3965 ModestMailOperationPrivate *priv = NULL;
3967 g_return_val_if_fail (self, NULL);
3969 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3971 /* new operations don't have anything interesting */
3972 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3973 return g_strdup_printf ("%p <new operation>", self);
3975 switch (priv->op_type) {
3976 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3977 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
3978 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3979 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3980 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3981 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3982 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3983 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3984 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
3985 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3986 default: type = "UNEXPECTED"; break;
3989 switch (priv->status) {
3990 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3991 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3992 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3993 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3994 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3995 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3996 default: status= "UNEXPECTED"; break;
3999 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4001 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4002 priv->done, priv->total,
4003 priv->error && priv->error->message ? priv->error->message : "");
4007 * Once the mail operations were objects this will be no longer
4008 * needed. I don't like it, but we need it for the moment
4011 _check_memory_low (ModestMailOperation *mail_op)
4013 if (modest_platform_check_memory_low (NULL, FALSE)) {
4014 ModestMailOperationPrivate *priv;
4016 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4017 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4018 g_set_error (&(priv->error),
4019 MODEST_MAIL_OPERATION_ERROR,
4020 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4021 "Not enough memory to complete the operation");