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-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers, guint num_elements);
100 static int compare_headers_by_date (gconstpointer a,
103 static void sync_folder_finish_callback (TnyFolder *self,
108 static gboolean _check_memory_low (ModestMailOperation *mail_op);
110 /* Helpers for the update account operation (send & receive)*/
113 ModestMailOperation *mail_op;
115 UpdateAccountCallback callback;
120 TnyFolderObserver *inbox_observer;
121 RetrieveAllCallback retrieve_all_cb;
122 gboolean interactive;
126 static void destroy_update_account_info (UpdateAccountInfo *info);
128 static void update_account_send_mail (UpdateAccountInfo *info);
130 static void update_account_get_msg_async_cb (TnyFolder *folder,
136 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
137 TnyList *new_headers);
139 enum _ModestMailOperationSignals
141 PROGRESS_CHANGED_SIGNAL,
142 OPERATION_STARTED_SIGNAL,
143 OPERATION_FINISHED_SIGNAL,
147 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
148 struct _ModestMailOperationPrivate {
154 ErrorCheckingUserCallback error_checking;
155 gpointer error_checking_user_data;
156 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
157 ModestMailOperationStatus status;
158 ModestMailOperationTypeOperation op_type;
161 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
162 MODEST_TYPE_MAIL_OPERATION, \
163 ModestMailOperationPrivate))
165 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
166 priv->status = new_status;\
171 GetMsgAsyncUserCallback user_callback;
173 TnyIterator *more_msgs;
175 ModestMailOperation *mail_op;
176 GDestroyNotify destroy_notify;
177 gint last_total_bytes;
178 gint sum_total_bytes;
182 typedef struct _RefreshAsyncHelper {
183 ModestMailOperation *mail_op;
184 RefreshAsyncUserCallback user_callback;
186 } RefreshAsyncHelper;
188 typedef struct _XFerMsgsAsyncHelper
190 ModestMailOperation *mail_op;
192 TnyIterator *more_msgs;
193 TnyFolder *dest_folder;
194 XferMsgsAsyncUserCallback user_callback;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 } XFerMsgsAsyncHelper;
202 typedef struct _XFerFolderAsyncHelper
204 ModestMailOperation *mail_op;
205 XferFolderAsyncUserCallback user_callback;
207 } XFerFolderAsyncHelper;
209 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
213 static void modest_mail_operation_create_msg (ModestMailOperation *self,
214 const gchar *from, const gchar *to,
215 const gchar *cc, const gchar *bcc,
216 const gchar *subject, const gchar *plain_body,
217 const gchar *html_body, const GList *attachments_list,
218 const GList *images_list,
219 TnyHeaderFlags priority_flags,
220 ModestMailOperationCreateMsgCallback callback,
223 static gboolean idle_notify_queue (gpointer data);
226 ModestMailOperation *mail_op;
234 GList *attachments_list;
236 TnyHeaderFlags priority_flags;
237 ModestMailOperationCreateMsgCallback callback;
243 ModestMailOperation *mail_op;
245 ModestMailOperationCreateMsgCallback callback;
250 static GObjectClass *parent_class = NULL;
252 static guint signals[NUM_SIGNALS] = {0};
255 modest_mail_operation_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMailOperationClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_mail_operation_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMailOperation),
268 (GInstanceInitFunc) modest_mail_operation_init,
271 my_type = g_type_register_static (G_TYPE_OBJECT,
272 "ModestMailOperation",
279 modest_mail_operation_class_init (ModestMailOperationClass *klass)
281 GObjectClass *gobject_class;
282 gobject_class = (GObjectClass*) klass;
284 parent_class = g_type_class_peek_parent (klass);
285 gobject_class->finalize = modest_mail_operation_finalize;
287 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
290 * ModestMailOperation::progress-changed
291 * @self: the #MailOperation that emits the signal
292 * @user_data: user data set when the signal handler was connected
294 * Emitted when the progress of a mail operation changes
296 signals[PROGRESS_CHANGED_SIGNAL] =
297 g_signal_new ("progress-changed",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
302 g_cclosure_marshal_VOID__POINTER,
303 G_TYPE_NONE, 1, G_TYPE_POINTER);
307 * This signal is issued whenever a mail operation starts, and
308 * starts mean when the tinymail operation is issued. This
309 * means that it could happen that something wrong happens and
310 * the tinymail function is never called. In this situation a
311 * operation-finished will be issued without any
314 signals[OPERATION_STARTED_SIGNAL] =
315 g_signal_new ("operation-started",
316 G_TYPE_FROM_CLASS (gobject_class),
318 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
320 g_cclosure_marshal_VOID__VOID,
325 * This signal is issued whenever a mail operation
326 * finishes. Note that this signal could be issued without any
327 * previous "operation-started" signal, because this last one
328 * is only issued when the tinymail operation is successfully
331 signals[OPERATION_FINISHED_SIGNAL] =
332 g_signal_new ("operation-finished",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
337 g_cclosure_marshal_VOID__VOID,
342 modest_mail_operation_init (ModestMailOperation *obj)
344 ModestMailOperationPrivate *priv;
346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
348 priv->account = NULL;
349 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
355 priv->error_checking = NULL;
356 priv->error_checking_user_data = NULL;
360 modest_mail_operation_finalize (GObject *obj)
362 ModestMailOperationPrivate *priv;
364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
369 g_error_free (priv->error);
373 g_object_unref (priv->source);
377 g_object_unref (priv->account);
378 priv->account = NULL;
382 G_OBJECT_CLASS(parent_class)->finalize (obj);
386 modest_mail_operation_new (GObject *source)
388 ModestMailOperation *obj;
389 ModestMailOperationPrivate *priv;
391 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
395 priv->source = g_object_ref(source);
401 modest_mail_operation_new_with_error_handling (GObject *source,
402 ErrorCheckingUserCallback error_handler,
404 ErrorCheckingUserDataDestroyer error_handler_destroyer)
406 ModestMailOperation *obj;
407 ModestMailOperationPrivate *priv;
409 obj = modest_mail_operation_new (source);
410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 g_return_val_if_fail (error_handler != NULL, obj);
413 priv->error_checking = error_handler;
414 priv->error_checking_user_data = user_data;
415 priv->error_checking_user_data_destroyer = error_handler_destroyer;
421 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
423 ModestMailOperationPrivate *priv;
425 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
428 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
430 /* Call the user callback */
431 if (priv->error_checking != NULL)
432 priv->error_checking (self, priv->error_checking_user_data);
436 ModestMailOperationTypeOperation
437 modest_mail_operation_get_type_operation (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
442 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
446 return priv->op_type;
450 modest_mail_operation_is_mine (ModestMailOperation *self,
453 ModestMailOperationPrivate *priv;
455 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
459 if (priv->source == NULL) return FALSE;
461 return priv->source == me;
465 modest_mail_operation_get_source (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
474 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
478 return (priv->source) ? g_object_ref (priv->source) : NULL;
481 ModestMailOperationStatus
482 modest_mail_operation_get_status (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
487 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
488 MODEST_MAIL_OPERATION_STATUS_INVALID);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
492 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
493 return MODEST_MAIL_OPERATION_STATUS_INVALID;
500 modest_mail_operation_get_error (ModestMailOperation *self)
502 ModestMailOperationPrivate *priv;
504 g_return_val_if_fail (self, NULL);
505 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
510 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
518 modest_mail_operation_cancel (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
521 gboolean canceled = FALSE;
523 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
528 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
530 /* Cancel the mail operation */
531 g_return_val_if_fail (priv->account, FALSE);
532 tny_account_cancel (priv->account);
534 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
535 ModestTnySendQueue *queue;
536 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
539 /* Cancel the sending of the following next messages */
540 if (TNY_IS_SEND_QUEUE (queue))
541 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
548 modest_mail_operation_get_task_done (ModestMailOperation *self)
550 ModestMailOperationPrivate *priv;
552 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
560 modest_mail_operation_get_task_total (ModestMailOperation *self)
562 ModestMailOperationPrivate *priv;
564 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
572 modest_mail_operation_is_finished (ModestMailOperation *self)
574 ModestMailOperationPrivate *priv;
575 gboolean retval = FALSE;
577 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
582 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
583 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
584 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
585 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
595 * Creates an image of the current state of a mail operation, the
596 * caller must free it
598 static ModestMailOperationState *
599 modest_mail_operation_clone_state (ModestMailOperation *self)
601 ModestMailOperationState *state;
602 ModestMailOperationPrivate *priv;
604 /* FIXME: this should be fixed properly
606 * in some cases, priv was NULL, so checking here to
609 g_return_val_if_fail (self, NULL);
610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
611 g_return_val_if_fail (priv, NULL);
616 state = g_slice_new (ModestMailOperationState);
618 state->status = priv->status;
619 state->op_type = priv->op_type;
620 state->done = priv->done;
621 state->total = priv->total;
622 state->finished = modest_mail_operation_is_finished (self);
623 state->bytes_done = 0;
624 state->bytes_total = 0;
629 /* ******************************************************************* */
630 /* ************************** SEND ACTIONS ************************* */
631 /* ******************************************************************* */
635 ModestMailOperation *mail_op;
640 send_mail_common_cb (gboolean cancelled,
642 SendNewMailHelper *helper)
644 ModestMailOperationPrivate *priv;
645 ModestMailOperation *self;
647 self = helper->mail_op;
648 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
650 if (cancelled || err)
654 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
655 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
656 "Error adding a msg to the send queue\n");
657 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
659 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
664 modest_mail_operation_notify_end (self);
666 g_object_unref (helper->mail_op);
667 g_slice_free (SendNewMailHelper, helper);
671 send_mail_on_sync_async_cb (TnyFolder *self,
676 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
680 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
686 send_mail_common_cb (cancelled, err, (SendNewMailHelper *) user_data);
690 idle_create_msg_cb (gpointer idle_data)
692 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
694 /* This is a GDK lock because we are an idle callback and
695 * info->callback can contain Gtk+ code */
697 gdk_threads_enter (); /* CHECKED */
698 info->callback (info->mail_op, info->msg, info->userdata);
700 g_object_unref (info->mail_op);
702 g_object_unref (info->msg);
703 g_slice_free (CreateMsgIdleInfo, info);
704 gdk_threads_leave (); /* CHECKED */
710 create_msg_thread (gpointer thread_data)
712 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
713 TnyMsg *new_msg = NULL;
714 ModestMailOperationPrivate *priv;
717 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
718 if (info->html_body == NULL) {
719 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
720 info->bcc, info->subject, info->plain_body,
721 info->attachments_list, &attached,
724 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
725 info->bcc, info->subject, info->html_body,
726 info->plain_body, info->attachments_list,
727 info->images_list, &attached,
734 /* Set priority flags in message */
735 header = tny_msg_get_header (new_msg);
736 tny_header_set_flag (header, info->priority_flags);
738 /* Set attachment flags in message */
739 if (info->attachments_list != NULL && attached > 0)
740 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
742 g_object_unref (G_OBJECT(header));
744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
746 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
747 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
748 "modest: failed to create a new msg\n");
756 g_free (info->plain_body);
757 g_free (info->html_body);
758 g_free (info->subject);
759 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
760 g_list_free (info->attachments_list);
761 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
762 g_list_free (info->images_list);
764 if (info->callback) {
765 CreateMsgIdleInfo *idle_info;
766 idle_info = g_slice_new0 (CreateMsgIdleInfo);
767 idle_info->mail_op = g_object_ref (info->mail_op);
768 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
769 idle_info->callback = info->callback;
770 idle_info->userdata = info->userdata;
771 g_idle_add (idle_create_msg_cb, idle_info);
773 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
776 g_object_unref (info->mail_op);
777 g_slice_free (CreateMsgInfo, info);
778 if (new_msg) g_object_unref(new_msg);
784 modest_mail_operation_create_msg (ModestMailOperation *self,
785 const gchar *from, const gchar *to,
786 const gchar *cc, const gchar *bcc,
787 const gchar *subject, const gchar *plain_body,
788 const gchar *html_body,
789 const GList *attachments_list,
790 const GList *images_list,
791 TnyHeaderFlags priority_flags,
792 ModestMailOperationCreateMsgCallback callback,
795 CreateMsgInfo *info = NULL;
797 info = g_slice_new0 (CreateMsgInfo);
798 info->mail_op = g_object_ref (self);
800 info->from = g_strdup (from);
801 info->to = g_strdup (to);
802 info->cc = g_strdup (cc);
803 info->bcc = g_strdup (bcc);
804 info->subject = g_strdup (subject);
805 info->plain_body = g_strdup (plain_body);
806 info->html_body = g_strdup (html_body);
807 info->attachments_list = g_list_copy ((GList *) attachments_list);
808 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
809 info->images_list = g_list_copy ((GList *) images_list);
810 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
811 info->priority_flags = priority_flags;
813 info->callback = callback;
814 info->userdata = userdata;
816 g_thread_create (create_msg_thread, info, FALSE, NULL);
821 TnyTransportAccount *transport_account;
826 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
830 TnySendQueue *send_queue = NULL;
831 ModestMailOperationPrivate *priv = NULL;
832 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
833 TnyFolder *draft_folder = NULL;
834 TnyFolder *outbox_folder = NULL;
835 TnyHeader *header = NULL;
837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
840 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
841 modest_mail_operation_notify_end (self);
845 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
846 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
847 modest_mail_operation_notify_end (self);
851 /* Add message to send queue */
852 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
853 if (!TNY_IS_SEND_QUEUE(send_queue)) {
855 g_error_free (priv->error);
858 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
859 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
860 "modest: could not find send queue for account\n");
861 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
862 modest_mail_operation_notify_end (self);
865 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
866 helper->mail_op = g_object_ref (self);
867 helper->notify = (info->draft_msg == NULL);
869 /* Add the msg to the queue. The callback will free
871 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
873 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
877 if (info->draft_msg != NULL) {
878 TnyList *tmp_headers = NULL;
879 TnyFolder *folder = NULL;
880 TnyFolder *src_folder = NULL;
881 TnyFolderType folder_type;
882 TnyTransportAccount *transport_account = NULL;
883 SendNewMailHelper *helper = NULL;
885 /* To remove the old mail from its source folder, we need to get the
886 * transport account of the original draft message (the transport account
887 * might have been changed by the user) */
888 header = tny_msg_get_header (info->draft_msg);
889 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
890 modest_runtime_get_account_store(), header);
891 if (transport_account == NULL)
892 transport_account = g_object_ref(info->transport_account);
893 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
894 TNY_FOLDER_TYPE_DRAFTS);
895 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
896 TNY_FOLDER_TYPE_OUTBOX);
897 g_object_unref(transport_account);
900 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
902 modest_mail_operation_notify_end (self);
905 if (!outbox_folder) {
906 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
908 modest_mail_operation_notify_end (self);
912 folder = tny_msg_get_folder (info->draft_msg);
913 if (folder == NULL) {
914 modest_mail_operation_notify_end (self);
917 folder_type = modest_tny_folder_guess_folder_type (folder);
919 if (folder_type == TNY_FOLDER_TYPE_INVALID)
920 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
922 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
923 src_folder = outbox_folder;
925 src_folder = draft_folder;
927 /* Note: This can fail (with a warning) if the message is not really already in a folder,
928 * because this function requires it to have a UID. */
929 helper = g_slice_new (SendNewMailHelper);
930 helper->mail_op = g_object_ref (self);
931 helper->notify = TRUE;
933 tmp_headers = tny_simple_list_new ();
934 tny_list_append (tmp_headers, (GObject*) header);
935 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
936 g_object_unref (tmp_headers);
937 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
939 g_object_unref (folder);
944 g_object_unref (header);
946 g_object_unref (info->draft_msg);
948 g_object_unref (draft_folder);
950 g_object_unref (outbox_folder);
951 if (info->transport_account)
952 g_object_unref (info->transport_account);
953 g_slice_free (SendNewMailInfo, info);
957 modest_mail_operation_send_new_mail (ModestMailOperation *self,
958 TnyTransportAccount *transport_account,
960 const gchar *from, const gchar *to,
961 const gchar *cc, const gchar *bcc,
962 const gchar *subject, const gchar *plain_body,
963 const gchar *html_body,
964 const GList *attachments_list,
965 const GList *images_list,
966 TnyHeaderFlags priority_flags)
968 ModestMailOperationPrivate *priv = NULL;
969 SendNewMailInfo *info;
971 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
972 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
974 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
975 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
976 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
977 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
979 modest_mail_operation_notify_start (self);
981 /* Check parametters */
983 /* Set status failed and set an error */
984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
985 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
986 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
987 _("Error trying to send a mail. You need to set at least one recipient"));
988 modest_mail_operation_notify_end (self);
991 info = g_slice_new0 (SendNewMailInfo);
992 info->transport_account = transport_account;
993 if (transport_account)
994 g_object_ref (transport_account);
995 info->draft_msg = draft_msg;
997 g_object_ref (draft_msg);
1000 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1001 attachments_list, images_list, priority_flags,
1002 modest_mail_operation_send_new_mail_cb, info);
1008 TnyTransportAccount *transport_account;
1010 SaveToDraftstCallback callback;
1014 ModestMailOperation *mailop;
1015 } SaveToDraftsAddMsgInfo;
1018 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1023 ModestMailOperationPrivate *priv = NULL;
1024 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1025 GError *io_error = NULL;
1027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1029 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1030 io_error = priv->error;
1034 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1035 g_error_free(priv->error);
1038 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1040 if ((!priv->error) && (info->draft_msg != NULL)) {
1041 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1042 TnyFolder *src_folder = tny_header_get_folder (header);
1044 /* Remove the old draft */
1045 tny_folder_remove_msg (src_folder, header, NULL);
1047 /* Synchronize to expunge and to update the msg counts */
1048 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1049 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1051 g_object_unref (G_OBJECT(header));
1052 g_object_unref (G_OBJECT(src_folder));
1056 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1058 g_error_free (io_error);
1061 } else if (io_error) {
1062 priv->error = io_error;
1063 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1068 /* Call the user callback */
1070 info->callback (info->mailop, info->msg, info->user_data);
1072 if (info->transport_account)
1073 g_object_unref (G_OBJECT(info->transport_account));
1074 if (info->draft_msg)
1075 g_object_unref (G_OBJECT (info->draft_msg));
1077 g_object_unref (G_OBJECT(info->drafts));
1079 g_object_unref (G_OBJECT (info->msg));
1081 modest_mail_operation_notify_end (info->mailop);
1082 g_object_unref(info->mailop);
1083 g_slice_free (SaveToDraftsAddMsgInfo, info);
1088 TnyTransportAccount *transport_account;
1090 SaveToDraftstCallback callback;
1095 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1099 TnyFolder *drafts = NULL;
1100 ModestMailOperationPrivate *priv = NULL;
1101 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1103 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1106 if (!(priv->error)) {
1107 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1108 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1109 "modest: failed to create a new msg\n");
1112 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1113 TNY_FOLDER_TYPE_DRAFTS);
1114 if (!drafts && !(priv->error)) {
1115 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1116 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1117 "modest: failed to create a new msg\n");
1121 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1122 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1123 cb_info->transport_account = g_object_ref(info->transport_account);
1124 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1125 cb_info->callback = info->callback;
1126 cb_info->user_data = info->user_data;
1127 cb_info->drafts = g_object_ref(drafts);
1128 cb_info->msg = g_object_ref(msg);
1129 cb_info->mailop = g_object_ref(self);
1130 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1133 /* Call the user callback */
1134 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1136 info->callback (self, msg, info->user_data);
1137 modest_mail_operation_notify_end (self);
1141 g_object_unref (G_OBJECT(drafts));
1142 if (info->draft_msg)
1143 g_object_unref (G_OBJECT (info->draft_msg));
1144 if (info->transport_account)
1145 g_object_unref (G_OBJECT(info->transport_account));
1146 g_slice_free (SaveToDraftsInfo, info);
1150 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1151 TnyTransportAccount *transport_account,
1153 const gchar *from, const gchar *to,
1154 const gchar *cc, const gchar *bcc,
1155 const gchar *subject, const gchar *plain_body,
1156 const gchar *html_body,
1157 const GList *attachments_list,
1158 const GList *images_list,
1159 TnyHeaderFlags priority_flags,
1160 SaveToDraftstCallback callback,
1163 ModestMailOperationPrivate *priv = NULL;
1164 SaveToDraftsInfo *info = NULL;
1166 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1167 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1171 /* Get account and set it into mail_operation */
1172 priv->account = g_object_ref (transport_account);
1173 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1175 info = g_slice_new0 (SaveToDraftsInfo);
1176 info->transport_account = g_object_ref (transport_account);
1177 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1178 info->callback = callback;
1179 info->user_data = user_data;
1181 modest_mail_operation_notify_start (self);
1182 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1183 attachments_list, images_list, priority_flags,
1184 modest_mail_operation_save_to_drafts_cb, info);
1189 ModestMailOperation *mail_op;
1190 TnyMimePart *mime_part;
1192 GetMimePartSizeCallback callback;
1194 } GetMimePartSizeInfo;
1196 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1197 /* We use this folder observer to track the headers that have been
1198 * added to a folder */
1201 TnyList *new_headers;
1202 } InternalFolderObserver;
1205 GObjectClass parent;
1206 } InternalFolderObserverClass;
1208 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1210 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1211 internal_folder_observer,
1213 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1217 foreach_add_item (gpointer header, gpointer user_data)
1219 tny_list_prepend (TNY_LIST (user_data),
1223 /* This is the method that looks for new messages in a folder */
1225 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1227 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1229 TnyFolderChangeChanged changed;
1231 changed = tny_folder_change_get_changed (change);
1233 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1236 /* Get added headers */
1237 list = tny_simple_list_new ();
1238 tny_folder_change_get_added_headers (change, list);
1240 /* Add them to the folder observer */
1241 tny_list_foreach (list, foreach_add_item,
1242 derived->new_headers);
1244 g_object_unref (G_OBJECT (list));
1249 internal_folder_observer_init (InternalFolderObserver *self)
1251 self->new_headers = tny_simple_list_new ();
1254 internal_folder_observer_finalize (GObject *object)
1256 InternalFolderObserver *self;
1258 self = (InternalFolderObserver *) object;
1259 g_object_unref (self->new_headers);
1261 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1264 tny_folder_observer_init (TnyFolderObserverIface *iface)
1266 iface->update = internal_folder_observer_update;
1269 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1271 GObjectClass *object_class;
1273 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1274 object_class = (GObjectClass*) klass;
1275 object_class->finalize = internal_folder_observer_finalize;
1279 destroy_update_account_info (UpdateAccountInfo *info)
1281 g_free (info->account_name);
1282 g_object_unref (info->folders);
1283 g_object_unref (info->mail_op);
1284 g_slice_free (UpdateAccountInfo, info);
1289 update_account_send_mail (UpdateAccountInfo *info)
1291 TnyTransportAccount *transport_account = NULL;
1293 /* Get the transport account */
1294 transport_account = (TnyTransportAccount *)
1295 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1296 info->account_name);
1298 if (transport_account) {
1299 ModestTnySendQueue *send_queue;
1303 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1304 g_object_unref (transport_account);
1306 if (TNY_IS_SEND_QUEUE (send_queue)) {
1307 /* Get outbox folder */
1308 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1309 if (outbox) { /* this could fail in some cases */
1310 num_messages = tny_folder_get_all_count (outbox);
1311 g_object_unref (outbox);
1313 g_warning ("%s: could not get outbox", __FUNCTION__);
1317 if (num_messages != 0) {
1318 /* Reenable suspended items */
1319 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1322 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1323 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1331 update_account_get_msg_async_cb (TnyFolder *folder,
1337 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1338 ModestMailOperationPrivate *priv;
1340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1343 if (TNY_IS_MSG (msg)) {
1344 TnyHeader *header = tny_msg_get_header (msg);
1347 ModestMailOperationState *state;
1348 state = modest_mail_operation_clone_state (msg_info->mail_op);
1349 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1350 state->bytes_done = msg_info->sum_total_bytes;
1351 state->bytes_total = msg_info->total_bytes;
1353 /* Notify the status change. Only notify about changes
1354 referred to bytes */
1355 g_signal_emit (G_OBJECT (msg_info->mail_op),
1356 signals[PROGRESS_CHANGED_SIGNAL],
1359 g_object_unref (header);
1360 g_slice_free (ModestMailOperationState, state);
1364 if (priv->done == priv->total) {
1365 TnyList *new_headers;
1366 UpdateAccountInfo *info;
1368 /* After getting all the messages send the ones in the
1370 info = (UpdateAccountInfo *) msg_info->user_data;
1371 update_account_send_mail (info);
1373 /* Check if the operation was a success */
1375 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1377 /* Call the user callback and free */
1378 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1379 update_account_notify_user_and_free (info, new_headers);
1380 g_object_unref (new_headers);
1382 /* Delete the helper */
1383 g_object_unref (msg_info->more_msgs);
1384 g_object_unref (msg_info->mail_op);
1385 g_slice_free (GetMsgInfo, msg_info);
1390 update_account_notify_user_and_free (UpdateAccountInfo *info,
1391 TnyList *new_headers)
1393 /* Set the account back to not busy */
1394 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1395 info->account_name, FALSE);
1399 info->callback (info->mail_op, new_headers, info->user_data);
1401 /* Mail operation end */
1402 modest_mail_operation_notify_end (info->mail_op);
1406 g_object_unref (new_headers);
1407 destroy_update_account_info (info);
1411 inbox_refreshed_cb (TnyFolder *inbox,
1416 UpdateAccountInfo *info;
1417 ModestMailOperationPrivate *priv;
1418 TnyIterator *new_headers_iter;
1419 GPtrArray *new_headers_array = NULL;
1420 gint max_size, retrieve_limit, i;
1421 ModestAccountMgr *mgr;
1422 ModestAccountRetrieveType retrieve_type;
1423 TnyList *new_headers = NULL;
1424 gboolean headers_only, ignore_limit;
1426 info = (UpdateAccountInfo *) user_data;
1427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1428 mgr = modest_runtime_get_account_mgr ();
1430 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1431 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1433 if (canceled || err) {
1434 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1436 priv->error = g_error_copy (err);
1438 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1439 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1442 tny_folder_remove_observer (inbox, info->inbox_observer);
1443 g_object_unref (info->inbox_observer);
1444 info->inbox_observer = NULL;
1446 /* Notify the user about the error and then exit */
1447 update_account_notify_user_and_free (info, NULL);
1452 /* Try to send anyway */
1456 /* Get the message max size */
1457 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1458 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1460 max_size = G_MAXINT;
1462 max_size = max_size * KB;
1464 /* Create the new headers array. We need it to sort the
1465 new headers by date */
1466 new_headers_array = g_ptr_array_new ();
1467 if (info->inbox_observer) {
1468 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1469 while (!tny_iterator_is_done (new_headers_iter)) {
1470 TnyHeader *header = NULL;
1472 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1473 /* Apply per-message size limits */
1474 if (tny_header_get_message_size (header) < max_size)
1475 g_ptr_array_add (new_headers_array, g_object_ref (header));
1477 g_object_unref (header);
1478 tny_iterator_next (new_headers_iter);
1480 g_object_unref (new_headers_iter);
1482 tny_folder_remove_observer (inbox, info->inbox_observer);
1483 g_object_unref (info->inbox_observer);
1484 info->inbox_observer = NULL;
1487 if (new_headers_array->len == 0) {
1488 g_ptr_array_free (new_headers_array, FALSE);
1492 /* Get per-account message amount retrieval limit */
1493 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1494 if (retrieve_limit == 0)
1495 retrieve_limit = G_MAXINT;
1497 /* Get per-account retrieval type */
1498 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1499 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1502 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1504 /* Ask the users if they want to retrieve all the messages
1505 even though the limit was exceeded */
1506 ignore_limit = FALSE;
1507 if (new_headers_array->len > retrieve_limit) {
1508 /* Ask the user if a callback has been specified and
1509 if the mail operation has a source (this means that
1510 was invoked by the user and not automatically by a
1512 if (info->retrieve_all_cb && priv->source)
1513 ignore_limit = info->retrieve_all_cb (priv->source,
1514 new_headers_array->len,
1518 /* Copy the headers to a list and free the array */
1519 new_headers = tny_simple_list_new ();
1520 for (i=0; i < new_headers_array->len; i++) {
1521 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1522 tny_list_append (new_headers, G_OBJECT (header));
1524 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1525 g_ptr_array_free (new_headers_array, FALSE);
1527 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1530 GetMsgInfo *msg_info;
1534 priv->total = tny_list_get_length (new_headers);
1536 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1538 iter = tny_list_create_iterator (new_headers);
1540 /* Create the message info */
1541 msg_info = g_slice_new0 (GetMsgInfo);
1542 msg_info->mail_op = g_object_ref (info->mail_op);
1543 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1544 msg_info->more_msgs = g_object_ref (iter);
1545 msg_info->user_data = info;
1547 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1548 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1549 TnyFolder *folder = tny_header_get_folder (header);
1551 /* Get message in an async way */
1552 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1555 g_object_unref (folder);
1558 tny_iterator_next (iter);
1560 g_object_unref (iter);
1562 /* The mail operation will finish when the last
1563 message is retrieved */
1567 /* If we don't have to retrieve the new messages then
1569 update_account_send_mail (info);
1571 /* Check if the operation was a success */
1573 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1575 /* Call the user callback and free */
1576 update_account_notify_user_and_free (info, new_headers);
1580 inbox_refresh_status_update (GObject *obj,
1584 UpdateAccountInfo *info = NULL;
1585 ModestMailOperation *self = NULL;
1586 ModestMailOperationPrivate *priv = NULL;
1587 ModestMailOperationState *state;
1589 g_return_if_fail (user_data != NULL);
1590 g_return_if_fail (status != NULL);
1592 /* Show only the status information we want */
1593 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1596 info = (UpdateAccountInfo *) user_data;
1597 self = info->mail_op;
1598 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1602 priv->done = status->position;
1603 priv->total = status->of_total;
1605 state = modest_mail_operation_clone_state (self);
1607 /* This is not a GDK lock because we are a Tinymail callback and
1608 * Tinymail already acquires the Gdk lock */
1609 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1611 g_slice_free (ModestMailOperationState, state);
1615 recurse_folders_async_cb (TnyFolderStore *folder_store,
1621 UpdateAccountInfo *info;
1622 ModestMailOperationPrivate *priv;
1624 info = (UpdateAccountInfo *) user_data;
1625 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1627 if (err || canceled) {
1628 /* If the error was previosly set by another callback
1629 don't set it again */
1631 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1633 priv->error = g_error_copy (err);
1635 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1636 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1640 /* We're not getting INBOX children if we don't want to poke all */
1641 TnyIterator *iter = tny_list_create_iterator (list);
1642 while (!tny_iterator_is_done (iter)) {
1643 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1645 /* Add to the list of all folders */
1646 tny_list_append (info->folders, (GObject *) folder);
1648 if (info->poke_all) {
1649 TnyList *folders = tny_simple_list_new ();
1650 /* Add pending call */
1651 info->pending_calls++;
1653 tny_folder_store_get_folders_async (folder, folders, NULL,
1654 recurse_folders_async_cb,
1656 g_object_unref (folders);
1659 g_object_unref (G_OBJECT (folder));
1661 tny_iterator_next (iter);
1663 g_object_unref (G_OBJECT (iter));
1666 /* Remove my own pending call */
1667 info->pending_calls--;
1669 /* This means that we have all the folders */
1670 if (info->pending_calls == 0) {
1671 TnyIterator *iter_all_folders;
1672 TnyFolder *inbox = NULL;
1674 /* If there was any error do not continue */
1676 update_account_notify_user_and_free (info, NULL);
1680 iter_all_folders = tny_list_create_iterator (info->folders);
1682 /* Do a poke status over all folders */
1683 while (!tny_iterator_is_done (iter_all_folders) &&
1684 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1685 TnyFolder *folder = NULL;
1687 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1689 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1690 /* Get a reference to the INBOX */
1691 inbox = g_object_ref (folder);
1693 /* Issue a poke status over the folder */
1695 tny_folder_poke_status (folder);
1698 /* Free and go to next */
1699 g_object_unref (folder);
1700 tny_iterator_next (iter_all_folders);
1702 g_object_unref (iter_all_folders);
1704 /* Refresh the INBOX */
1706 /* Refresh the folder. Our observer receives
1707 * the new emails during folder refreshes, so
1708 * we can use observer->new_headers
1710 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1711 tny_folder_add_observer (inbox, info->inbox_observer);
1713 /* Refresh the INBOX */
1714 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1715 g_object_unref (inbox);
1717 /* We could not perform the inbox refresh but
1718 we'll try to send mails anyway */
1719 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1725 modest_mail_operation_update_account (ModestMailOperation *self,
1726 const gchar *account_name,
1728 gboolean interactive,
1729 RetrieveAllCallback retrieve_all_cb,
1730 UpdateAccountCallback callback,
1733 UpdateAccountInfo *info = NULL;
1734 ModestMailOperationPrivate *priv = NULL;
1735 ModestTnyAccountStore *account_store = NULL;
1737 ModestMailOperationState *state;
1739 /* Init mail operation */
1740 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1744 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1746 /* Get the store account */
1747 account_store = modest_runtime_get_account_store ();
1749 modest_tny_account_store_get_server_account (account_store,
1751 TNY_ACCOUNT_TYPE_STORE);
1753 /* The above function could return NULL */
1754 if (!priv->account) {
1755 /* Check if the operation was a success */
1756 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1757 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1759 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1761 /* Call the user callback */
1763 callback (self, NULL, user_data);
1765 /* Notify about operation end */
1766 modest_mail_operation_notify_end (self);
1771 /* We have once seen priv->account getting finalized during this code,
1772 * therefore adding a reference (bug #82296) */
1774 g_object_ref (priv->account);
1776 /* Create the helper object */
1777 info = g_slice_new0 (UpdateAccountInfo);
1778 info->pending_calls = 1;
1779 info->folders = tny_simple_list_new ();
1780 info->mail_op = g_object_ref (self);
1781 info->poke_all = poke_all;
1782 info->interactive = interactive;
1783 info->account_name = g_strdup (account_name);
1784 info->callback = callback;
1785 info->user_data = user_data;
1786 info->retrieve_all_cb = retrieve_all_cb;
1788 /* Set account busy */
1789 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1790 modest_mail_operation_notify_start (self);
1792 /* notify about the start of the operation */
1793 state = modest_mail_operation_clone_state (self);
1797 /* Start notifying progress */
1798 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1799 g_slice_free (ModestMailOperationState, state);
1801 /* Get all folders and continue in the callback */
1802 folders = tny_simple_list_new ();
1803 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1805 recurse_folders_async_cb,
1807 g_object_unref (folders);
1809 g_object_unref (priv->account);
1814 * Used to notify the queue from the main
1815 * loop. We call it inside an idle call to achieve that
1818 idle_notify_queue (gpointer data)
1820 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1822 gdk_threads_enter ();
1823 modest_mail_operation_notify_end (mail_op);
1824 gdk_threads_leave ();
1825 g_object_unref (mail_op);
1831 compare_headers_by_date (gconstpointer a,
1834 TnyHeader **header1, **header2;
1835 time_t sent1, sent2;
1837 header1 = (TnyHeader **) a;
1838 header2 = (TnyHeader **) b;
1840 sent1 = tny_header_get_date_sent (*header1);
1841 sent2 = tny_header_get_date_sent (*header2);
1843 /* We want the most recent ones (greater time_t) at the
1852 /* ******************************************************************* */
1853 /* ************************** STORE ACTIONS ************************* */
1854 /* ******************************************************************* */
1857 ModestMailOperation *mail_op;
1858 CreateFolderUserCallback callback;
1864 create_folder_cb (TnyFolderStore *parent_folder,
1866 TnyFolder *new_folder,
1870 ModestMailOperationPrivate *priv;
1871 CreateFolderInfo *info;
1873 info = (CreateFolderInfo *) user_data;
1874 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1876 if (canceled || err) {
1877 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1879 priv->error = g_error_copy (err);
1881 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1882 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1885 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1888 /* The user will unref the new_folder */
1890 info->callback (info->mail_op, parent_folder,
1891 new_folder, info->user_data);
1893 /* Notify about operation end */
1894 modest_mail_operation_notify_end (info->mail_op);
1897 g_object_unref (info->mail_op);
1898 g_slice_free (CreateFolderInfo, info);
1902 modest_mail_operation_create_folder (ModestMailOperation *self,
1903 TnyFolderStore *parent,
1905 CreateFolderUserCallback callback,
1908 ModestMailOperationPrivate *priv;
1910 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1911 g_return_if_fail (name);
1913 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1914 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1915 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1916 g_object_ref (parent) :
1917 modest_tny_folder_get_account (TNY_FOLDER (parent));
1919 /* Check for already existing folder */
1920 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1924 _CS("ckdg_ib_folder_already_exists"));
1928 if (TNY_IS_FOLDER (parent)) {
1929 /* Check folder rules */
1930 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1931 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1932 /* Set status failed and set an error */
1933 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1934 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1935 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1936 _("mail_in_ui_folder_create_error"));
1940 if (!strcmp (name, " ") || strchr (name, '/')) {
1941 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1942 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1943 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1944 _("mail_in_ui_folder_create_error"));
1948 CreateFolderInfo *info;
1950 info = g_slice_new0 (CreateFolderInfo);
1951 info->mail_op = g_object_ref (self);
1952 info->callback = callback;
1953 info->user_data = user_data;
1955 modest_mail_operation_notify_start (self);
1957 /* Create the folder */
1958 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1961 /* Call the user callback anyway */
1963 callback (self, parent, NULL, user_data);
1964 /* Notify about operation end */
1965 modest_mail_operation_notify_end (self);
1970 modest_mail_operation_remove_folder (ModestMailOperation *self,
1972 gboolean remove_to_trash)
1974 ModestMailOperationPrivate *priv;
1975 ModestTnyFolderRules rules;
1977 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1978 g_return_if_fail (TNY_IS_FOLDER (folder));
1980 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1982 /* Check folder rules */
1983 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1984 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1985 /* Set status failed and set an error */
1986 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1987 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1988 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1989 _("mail_in_ui_folder_delete_error"));
1993 /* Get the account */
1994 priv->account = modest_tny_folder_get_account (folder);
1995 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1997 /* Delete folder or move to trash */
1998 if (remove_to_trash) {
1999 TnyFolder *trash_folder = NULL;
2000 trash_folder = modest_tny_account_get_special_folder (priv->account,
2001 TNY_FOLDER_TYPE_TRASH);
2002 /* TODO: error_handling */
2004 modest_mail_operation_notify_start (self);
2005 modest_mail_operation_xfer_folder (self, folder,
2006 TNY_FOLDER_STORE (trash_folder),
2008 g_object_unref (trash_folder);
2010 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2013 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2015 modest_mail_operation_notify_start (self);
2016 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2017 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2020 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2022 g_object_unref (parent);
2024 g_warning ("%s: could not get parent folder", __FUNCTION__);
2028 /* Notify about operation end */
2029 modest_mail_operation_notify_end (self);
2033 transfer_folder_status_cb (GObject *obj,
2037 ModestMailOperation *self;
2038 ModestMailOperationPrivate *priv;
2039 ModestMailOperationState *state;
2040 XFerFolderAsyncHelper *helper;
2042 g_return_if_fail (status != NULL);
2044 /* Show only the status information we want */
2045 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2048 helper = (XFerFolderAsyncHelper *) user_data;
2049 g_return_if_fail (helper != NULL);
2051 self = helper->mail_op;
2052 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2054 priv->done = status->position;
2055 priv->total = status->of_total;
2057 state = modest_mail_operation_clone_state (self);
2059 /* This is not a GDK lock because we are a Tinymail callback
2060 * which is already GDK locked by Tinymail */
2062 /* no gdk_threads_enter (), CHECKED */
2064 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2066 /* no gdk_threads_leave (), CHECKED */
2068 g_slice_free (ModestMailOperationState, state);
2073 transfer_folder_cb (TnyFolder *folder,
2075 TnyFolderStore *into,
2076 TnyFolder *new_folder,
2080 XFerFolderAsyncHelper *helper;
2081 ModestMailOperation *self = NULL;
2082 ModestMailOperationPrivate *priv = NULL;
2084 helper = (XFerFolderAsyncHelper *) user_data;
2085 g_return_if_fail (helper != NULL);
2087 self = helper->mail_op;
2088 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2091 priv->error = g_error_copy (err);
2093 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2094 } else if (cancelled) {
2095 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2096 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2097 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2098 _("Transference of %s was cancelled."),
2099 tny_folder_get_name (folder));
2102 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2105 /* Notify about operation end */
2106 modest_mail_operation_notify_end (self);
2108 /* If user defined callback function was defined, call it */
2109 if (helper->user_callback) {
2111 /* This is not a GDK lock because we are a Tinymail callback
2112 * which is already GDK locked by Tinymail */
2114 /* no gdk_threads_enter (), CHECKED */
2115 helper->user_callback (self, new_folder, helper->user_data);
2116 /* no gdk_threads_leave () , CHECKED */
2120 g_object_unref (helper->mail_op);
2121 g_slice_free (XFerFolderAsyncHelper, helper);
2126 * This function checks if the new name is a valid name for our local
2127 * folders account. The new name could not be the same than then name
2128 * of any of the mandatory local folders
2130 * We can not rely on tinymail because tinymail does not check the
2131 * name of the virtual folders that the account could have in the case
2132 * that we're doing a rename (because it directly calls Camel which
2133 * knows nothing about our virtual folders).
2135 * In the case of an actual copy/move (i.e. move/copy a folder between
2136 * accounts) tinymail uses the tny_folder_store_create_account which
2137 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2138 * checks the new name of the folder, so this call in that case
2139 * wouldn't be needed. *But* NOTE that if tinymail changes its
2140 * implementation (if folder transfers within the same account is no
2141 * longer implemented as a rename) this call will allow Modest to work
2144 * If the new name is not valid, this function will set the status to
2145 * failed and will set also an error in the mail operation
2148 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2149 TnyFolderStore *into,
2150 const gchar *new_name)
2152 if (TNY_IS_ACCOUNT (into) &&
2153 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2154 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2156 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2157 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2158 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2159 _CS("ckdg_ib_folder_already_exists"));
2166 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2168 TnyFolderStore *parent,
2169 gboolean delete_original,
2170 XferFolderAsyncUserCallback user_callback,
2173 ModestMailOperationPrivate *priv = NULL;
2174 ModestTnyFolderRules parent_rules = 0, rules;
2175 XFerFolderAsyncHelper *helper = NULL;
2176 const gchar *folder_name = NULL;
2177 const gchar *error_msg;
2179 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2180 g_return_if_fail (TNY_IS_FOLDER (folder));
2181 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2183 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2184 folder_name = tny_folder_get_name (folder);
2186 /* Set the error msg */
2187 error_msg = _("mail_in_ui_folder_move_target_error");
2189 /* Get account and set it into mail_operation */
2190 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2191 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2192 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2194 /* Get folder rules */
2195 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2196 if (TNY_IS_FOLDER (parent))
2197 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2199 /* Apply operation constraints */
2200 if ((gpointer) parent == (gpointer) folder ||
2201 (!TNY_IS_FOLDER_STORE (parent)) ||
2202 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2205 } else if (TNY_IS_FOLDER (parent) &&
2206 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2210 } else if (TNY_IS_FOLDER (parent) &&
2211 TNY_IS_FOLDER_STORE (folder) &&
2212 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2213 TNY_FOLDER_STORE (folder))) {
2214 /* Do not move a parent into a child */
2216 } else if (TNY_IS_FOLDER_STORE (parent) &&
2217 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2218 /* Check that the new folder name is not used by any
2221 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2222 /* Check that the new folder name is not used by any
2223 special local folder */
2226 /* Create the helper */
2227 helper = g_slice_new0 (XFerFolderAsyncHelper);
2228 helper->mail_op = g_object_ref (self);
2229 helper->user_callback = user_callback;
2230 helper->user_data = user_data;
2232 /* Move/Copy folder */
2233 modest_mail_operation_notify_start (self);
2234 tny_folder_copy_async (folder,
2236 tny_folder_get_name (folder),
2239 transfer_folder_status_cb,
2245 /* Set status failed and set an error */
2246 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2247 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2248 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2251 /* Call the user callback if exists */
2253 user_callback (self, NULL, user_data);
2255 /* Notify the queue */
2256 modest_mail_operation_notify_end (self);
2260 modest_mail_operation_rename_folder (ModestMailOperation *self,
2263 XferFolderAsyncUserCallback user_callback,
2266 ModestMailOperationPrivate *priv;
2267 ModestTnyFolderRules rules;
2268 XFerFolderAsyncHelper *helper;
2270 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2271 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2272 g_return_if_fail (name);
2274 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2276 /* Get account and set it into mail_operation */
2277 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2278 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2280 /* Check folder rules */
2281 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2282 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2284 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2287 TnyFolderStore *into;
2289 into = tny_folder_get_folder_store (folder);
2291 /* Check that the new folder name is not used by any
2292 special local folder */
2293 if (new_name_valid_if_local_account (priv, into, name)) {
2294 /* Create the helper */
2295 helper = g_slice_new0 (XFerFolderAsyncHelper);
2296 helper->mail_op = g_object_ref(self);
2297 helper->user_callback = user_callback;
2298 helper->user_data = user_data;
2300 /* Rename. Camel handles folder subscription/unsubscription */
2301 modest_mail_operation_notify_start (self);
2302 tny_folder_copy_async (folder, into, name, TRUE,
2304 transfer_folder_status_cb,
2306 g_object_unref (into);
2308 g_object_unref (into);
2315 /* Set status failed and set an error */
2316 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2318 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2319 _("FIXME: unable to rename"));
2322 user_callback (self, NULL, user_data);
2324 /* Notify about operation end */
2325 modest_mail_operation_notify_end (self);
2328 /* ******************************************************************* */
2329 /* ************************** MSG ACTIONS ************************* */
2330 /* ******************************************************************* */
2333 modest_mail_operation_get_msg (ModestMailOperation *self,
2335 gboolean progress_feedback,
2336 GetMsgAsyncUserCallback user_callback,
2339 GetMsgInfo *helper = NULL;
2341 ModestMailOperationPrivate *priv;
2343 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2344 g_return_if_fail (TNY_IS_HEADER (header));
2346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2347 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2351 /* Check memory low */
2352 if (_check_memory_low (self)) {
2354 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2355 modest_mail_operation_notify_end (self);
2359 /* Get account and set it into mail_operation */
2360 folder = tny_header_get_folder (header);
2361 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2363 /* Check for cached messages */
2364 if (progress_feedback) {
2365 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2366 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2368 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2370 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2373 /* Create the helper */
2374 helper = g_slice_new0 (GetMsgInfo);
2375 helper->header = g_object_ref (header);
2376 helper->mail_op = g_object_ref (self);
2377 helper->user_callback = user_callback;
2378 helper->user_data = user_data;
2379 helper->destroy_notify = NULL;
2380 helper->last_total_bytes = 0;
2381 helper->sum_total_bytes = 0;
2382 helper->total_bytes = tny_header_get_message_size (header);
2383 helper->more_msgs = NULL;
2385 modest_mail_operation_notify_start (self);
2387 /* notify about the start of the operation */
2388 ModestMailOperationState *state;
2389 state = modest_mail_operation_clone_state (self);
2392 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2394 g_slice_free (ModestMailOperationState, state);
2396 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2398 g_object_unref (G_OBJECT (folder));
2402 get_msg_status_cb (GObject *obj,
2406 GetMsgInfo *helper = NULL;
2408 g_return_if_fail (status != NULL);
2410 /* Show only the status information we want */
2411 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2414 helper = (GetMsgInfo *) user_data;
2415 g_return_if_fail (helper != NULL);
2417 /* Notify progress */
2418 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2419 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2423 get_msg_async_cb (TnyFolder *folder,
2429 GetMsgInfo *info = NULL;
2430 ModestMailOperationPrivate *priv = NULL;
2433 info = (GetMsgInfo *) user_data;
2435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2438 if (info->more_msgs) {
2439 tny_iterator_next (info->more_msgs);
2440 finished = (tny_iterator_is_done (info->more_msgs));
2442 finished = (priv->done == priv->total) ? TRUE : FALSE;
2445 /* If canceled by the user, ignore the error given by Tinymail */
2449 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2451 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2453 priv->error = g_error_copy ((const GError *) err);
2454 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2457 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2458 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2461 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2462 /* Set the success status before calling the user callback */
2463 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2467 /* Call the user callback */
2468 if (info->user_callback)
2469 info->user_callback (info->mail_op, info->header, canceled,
2470 msg, err, info->user_data);
2472 /* Notify about operation end if this is the last callback */
2474 /* Free user data */
2475 if (info->destroy_notify)
2476 info->destroy_notify (info->user_data);
2478 /* Notify about operation end */
2479 modest_mail_operation_notify_end (info->mail_op);
2482 if (info->more_msgs)
2483 g_object_unref (info->more_msgs);
2484 g_object_unref (info->header);
2485 g_object_unref (info->mail_op);
2486 g_slice_free (GetMsgInfo, info);
2487 } else if (info->more_msgs) {
2488 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2489 TnyFolder *folder = tny_header_get_folder (header);
2491 g_object_unref (info->header);
2492 info->header = g_object_ref (header);
2494 /* Retrieve the next message */
2495 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2497 g_object_unref (header);
2498 g_object_unref (folder);
2500 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2505 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2506 TnyList *header_list,
2507 GetMsgAsyncUserCallback user_callback,
2509 GDestroyNotify notify)
2511 ModestMailOperationPrivate *priv = NULL;
2513 TnyIterator *iter = NULL;
2514 gboolean has_uncached_messages;
2516 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2518 /* Init mail operation */
2519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2520 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2522 priv->total = tny_list_get_length(header_list);
2524 /* Check memory low */
2525 if (_check_memory_low (self)) {
2526 if (user_callback) {
2527 TnyHeader *header = NULL;
2530 if (tny_list_get_length (header_list) > 0) {
2531 iter = tny_list_create_iterator (header_list);
2532 header = (TnyHeader *) tny_iterator_get_current (iter);
2533 g_object_unref (iter);
2535 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2537 g_object_unref (header);
2541 /* Notify about operation end */
2542 modest_mail_operation_notify_end (self);
2546 /* Check uncached messages */
2547 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2548 !has_uncached_messages && !tny_iterator_is_done (iter);
2549 tny_iterator_next (iter)) {
2552 header = (TnyHeader *) tny_iterator_get_current (iter);
2553 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2554 has_uncached_messages = TRUE;
2555 g_object_unref (header);
2557 g_object_unref (iter);
2558 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2560 /* Get account and set it into mail_operation */
2561 if (tny_list_get_length (header_list) >= 1) {
2562 TnyIterator *iterator = tny_list_create_iterator (header_list);
2563 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2565 TnyFolder *folder = tny_header_get_folder (header);
2567 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2568 g_object_unref (folder);
2570 g_object_unref (header);
2572 g_object_unref (iterator);
2575 msg_list_size = compute_message_list_size (header_list, 0);
2577 modest_mail_operation_notify_start (self);
2578 iter = tny_list_create_iterator (header_list);
2579 if (!tny_iterator_is_done (iter)) {
2580 /* notify about the start of the operation */
2581 ModestMailOperationState *state;
2582 state = modest_mail_operation_clone_state (self);
2585 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2588 GetMsgInfo *msg_info = NULL;
2589 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2590 TnyFolder *folder = tny_header_get_folder (header);
2592 /* Create the message info */
2593 msg_info = g_slice_new0 (GetMsgInfo);
2594 msg_info->mail_op = g_object_ref (self);
2595 msg_info->header = g_object_ref (header);
2596 msg_info->more_msgs = g_object_ref (iter);
2597 msg_info->user_callback = user_callback;
2598 msg_info->user_data = user_data;
2599 msg_info->destroy_notify = notify;
2600 msg_info->last_total_bytes = 0;
2601 msg_info->sum_total_bytes = 0;
2602 msg_info->total_bytes = msg_list_size;
2604 /* The callback will call it per each header */
2605 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2607 /* Free and go on */
2608 g_object_unref (header);
2609 g_object_unref (folder);
2610 g_slice_free (ModestMailOperationState, state);
2612 g_object_unref (iter);
2617 remove_msgs_async_cb (TnyFolder *folder,
2622 gboolean expunge, leave_on_server;
2623 const gchar *account_name;
2625 TnyAccount *account;
2626 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2627 ModestMailOperation *self;
2628 ModestMailOperationPrivate *priv;
2630 self = (ModestMailOperation *) user_data;
2631 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2633 if (canceled || err) {
2634 /* If canceled by the user, ignore the error given by Tinymail */
2636 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2638 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2639 priv->error = g_error_copy ((const GError *) err);
2640 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2643 modest_mail_operation_notify_end (self);
2644 g_object_unref (self);
2648 account = tny_folder_get_account (folder);
2649 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2651 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2653 proto = tny_account_get_proto (account);
2654 g_object_unref (account);
2657 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2659 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2660 modest_tny_folder_is_remote_folder (folder) == FALSE)
2666 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2671 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2673 gboolean remove_to_trash /*ignored*/)
2675 TnyFolder *folder = NULL;
2676 ModestMailOperationPrivate *priv;
2677 TnyIterator *iter = NULL;
2678 TnyHeader *header = NULL;
2679 TnyList *remove_headers = NULL;
2680 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2682 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2683 g_return_if_fail (TNY_IS_LIST (headers));
2685 if (remove_to_trash)
2686 g_warning ("remove to trash is not implemented");
2688 if (tny_list_get_length(headers) == 0) {
2689 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2690 goto cleanup; /* nothing to do */
2693 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2694 remove_headers = g_object_ref(headers);
2696 /* Get folder from first header and sync it */
2697 iter = tny_list_create_iterator (headers);
2698 header = TNY_HEADER (tny_iterator_get_current (iter));
2700 folder = tny_header_get_folder (header);
2701 if (!TNY_IS_FOLDER(folder)) {
2702 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2706 /* Don't remove messages that are being sent */
2707 if (modest_tny_folder_is_local_folder (folder)) {
2708 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2710 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2711 TnyTransportAccount *traccount = NULL;
2712 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2713 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2715 ModestTnySendQueueStatus status;
2716 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2718 if (TNY_IS_SEND_QUEUE (send_queue)) {
2719 TnyIterator *iter = tny_list_create_iterator(headers);
2720 g_object_unref(remove_headers);
2721 remove_headers = TNY_LIST(tny_simple_list_new());
2722 while (!tny_iterator_is_done(iter)) {
2724 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2725 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2726 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2727 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2728 tny_list_append(remove_headers, G_OBJECT(hdr));
2730 g_object_unref(hdr);
2732 tny_iterator_next(iter);
2734 g_object_unref(iter);
2736 g_object_unref(traccount);
2740 /* Get account and set it into mail_operation */
2741 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2742 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2745 /* remove message from folder */
2746 modest_mail_operation_notify_start (self);
2747 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2748 NULL, g_object_ref (self));
2752 g_object_unref (remove_headers);
2754 g_object_unref (header);
2756 g_object_unref (iter);
2758 g_object_unref (folder);
2762 notify_progress_of_multiple_messages (ModestMailOperation *self,
2764 gint *last_total_bytes,
2765 gint *sum_total_bytes,
2767 gboolean increment_done)
2769 ModestMailOperationPrivate *priv;
2770 ModestMailOperationState *state;
2771 gboolean is_num_bytes = FALSE;
2773 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2775 /* We know that tinymail sends us information about
2776 * transferred bytes with this particular message
2778 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2779 * I just added the 'if' so we don't get runtime warning)
2781 if (status->message)
2782 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2784 state = modest_mail_operation_clone_state (self);
2785 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2786 /* We know that we're in a different message when the
2787 total number of bytes to transfer is different. Of
2788 course it could fail if we're transferring messages
2789 of the same size, but this is a workarround */
2790 if (status->of_total != *last_total_bytes) {
2791 /* We need to increment the done when there is
2792 no information about each individual
2793 message, we need to do this in message
2794 transfers, and we don't do it for getting
2798 *sum_total_bytes += *last_total_bytes;
2799 *last_total_bytes = status->of_total;
2801 state->bytes_done += status->position + *sum_total_bytes;
2802 state->bytes_total = total_bytes;
2804 /* Notify the status change. Only notify about changes
2805 referred to bytes */
2806 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2810 g_slice_free (ModestMailOperationState, state);
2814 transfer_msgs_status_cb (GObject *obj,
2818 XFerMsgsAsyncHelper *helper;
2820 g_return_if_fail (status != NULL);
2822 /* Show only the status information we want */
2823 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2826 helper = (XFerMsgsAsyncHelper *) user_data;
2827 g_return_if_fail (helper != NULL);
2829 /* Notify progress */
2830 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2831 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2835 transfer_msgs_sync_folder_cb (TnyFolder *self,
2840 XFerMsgsAsyncHelper *helper;
2841 /* We don't care here about the results of the
2843 helper = (XFerMsgsAsyncHelper *) user_data;
2845 /* Notify about operation end */
2846 modest_mail_operation_notify_end (helper->mail_op);
2848 /* If user defined callback function was defined, call it */
2849 if (helper->user_callback)
2850 helper->user_callback (helper->mail_op, helper->user_data);
2853 if (helper->more_msgs)
2854 g_object_unref (helper->more_msgs);
2855 if (helper->headers)
2856 g_object_unref (helper->headers);
2857 if (helper->dest_folder)
2858 g_object_unref (helper->dest_folder);
2859 if (helper->mail_op)
2860 g_object_unref (helper->mail_op);
2861 g_slice_free (XFerMsgsAsyncHelper, helper);
2865 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2867 XFerMsgsAsyncHelper *helper;
2868 ModestMailOperation *self;
2869 ModestMailOperationPrivate *priv;
2870 gboolean finished = TRUE;
2872 helper = (XFerMsgsAsyncHelper *) user_data;
2873 self = helper->mail_op;
2875 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2878 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2880 priv->error = g_error_copy (err);
2882 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2883 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2884 if (helper->more_msgs) {
2885 /* We'll transfer the next message in the list */
2886 tny_iterator_next (helper->more_msgs);
2887 if (!tny_iterator_is_done (helper->more_msgs)) {
2888 GObject *next_header;
2889 g_object_unref (helper->headers);
2890 helper->headers = tny_simple_list_new ();
2891 next_header = tny_iterator_get_current (helper->more_msgs);
2892 tny_list_append (helper->headers, next_header);
2893 g_object_unref (next_header);
2899 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2904 /* Synchronize the source folder contents. This should
2905 be done by tinymail but the camel_folder_sync it's
2906 actually disabled in transfer_msgs_thread_clean
2907 because it's supposed to cause hangs */
2908 tny_folder_sync_async (folder, helper->delete,
2909 transfer_msgs_sync_folder_cb,
2912 /* Transfer more messages */
2913 tny_folder_transfer_msgs_async (folder,
2915 helper->dest_folder,
2918 transfer_msgs_status_cb,
2923 /* Computes the size of the messages the headers in the list belongs
2924 to. If num_elements is different from 0 then it only takes into
2925 account the first num_elements for the calculation */
2927 compute_message_list_size (TnyList *headers,
2931 guint size = 0, element = 0;
2933 /* If num_elements is not valid then take all into account */
2934 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2935 num_elements = tny_list_get_length (headers);
2937 iter = tny_list_create_iterator (headers);
2938 while (!tny_iterator_is_done (iter) && element < num_elements) {
2939 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2940 size += tny_header_get_message_size (header);
2941 g_object_unref (header);
2942 tny_iterator_next (iter);
2945 g_object_unref (iter);
2951 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2954 gboolean delete_original,
2955 XferMsgsAsyncUserCallback user_callback,
2958 ModestMailOperationPrivate *priv = NULL;
2959 TnyIterator *iter = NULL;
2960 TnyFolder *src_folder = NULL;
2961 XFerMsgsAsyncHelper *helper = NULL;
2962 TnyHeader *header = NULL;
2963 ModestTnyFolderRules rules = 0;
2964 TnyAccount *dst_account = NULL;
2965 gboolean leave_on_server;
2966 ModestMailOperationState *state;
2968 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2969 g_return_if_fail (headers && TNY_IS_LIST (headers));
2970 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2972 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2973 priv->total = tny_list_get_length (headers);
2975 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2976 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2978 /* Apply folder rules */
2979 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2980 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2981 /* Set status failed and set an error */
2982 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2983 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2984 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2985 _CS("ckct_ib_unable_to_paste_here"));
2986 /* Notify the queue */
2987 modest_mail_operation_notify_end (self);
2991 /* Get source folder */
2992 iter = tny_list_create_iterator (headers);
2993 header = TNY_HEADER (tny_iterator_get_current (iter));
2995 src_folder = tny_header_get_folder (header);
2996 g_object_unref (header);
2998 g_object_unref (iter);
3000 if (src_folder == NULL) {
3001 /* Notify the queue */
3002 modest_mail_operation_notify_end (self);
3004 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3009 /* Check folder source and destination */
3010 if (src_folder == folder) {
3011 /* Set status failed and set an error */
3012 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3013 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3014 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3015 _("mail_in_ui_folder_copy_target_error"));
3017 /* Notify the queue */
3018 modest_mail_operation_notify_end (self);
3021 g_object_unref (src_folder);
3025 /* Create the helper */
3026 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3027 helper->mail_op = g_object_ref(self);
3028 helper->dest_folder = g_object_ref(folder);
3029 helper->user_callback = user_callback;
3030 helper->user_data = user_data;
3031 helper->last_total_bytes = 0;
3032 helper->sum_total_bytes = 0;
3033 helper->total_bytes = compute_message_list_size (headers, 0);
3035 /* Get account and set it into mail_operation */
3036 priv->account = modest_tny_folder_get_account (src_folder);
3037 dst_account = modest_tny_folder_get_account (folder);
3039 if (priv->account == dst_account) {
3040 /* Transfer all messages at once using the fast
3041 * method. Note that depending on the server this
3042 * might not be that fast, and might not be
3043 * user-cancellable either */
3044 helper->headers = g_object_ref (headers);
3045 helper->more_msgs = NULL;
3047 /* Transfer messages one by one so the user can cancel
3050 helper->headers = tny_simple_list_new ();
3051 helper->more_msgs = tny_list_create_iterator (headers);
3052 hdr = tny_iterator_get_current (helper->more_msgs);
3053 tny_list_append (helper->headers, hdr);
3054 g_object_unref (hdr);
3057 /* If leave_on_server is set to TRUE then don't use
3058 delete_original, we always pass FALSE. This is because
3059 otherwise tinymail will try to sync the source folder and
3060 this could cause an error if we're offline while
3061 transferring an already downloaded message from a POP
3063 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3064 MODEST_PROTOCOL_STORE_POP) {
3065 const gchar *account_name;
3067 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3068 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3071 leave_on_server = FALSE;
3074 /* Do not delete messages if leave on server is TRUE */
3075 helper->delete = (leave_on_server) ? FALSE : delete_original;
3077 modest_mail_operation_notify_start (self);
3079 /* Start notifying progress */
3080 state = modest_mail_operation_clone_state (self);
3083 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3084 g_slice_free (ModestMailOperationState, state);
3086 tny_folder_transfer_msgs_async (src_folder,
3091 transfer_msgs_status_cb,
3093 g_object_unref (src_folder);
3094 g_object_unref (dst_account);
3099 on_refresh_folder (TnyFolder *folder,
3104 RefreshAsyncHelper *helper = NULL;
3105 ModestMailOperation *self = NULL;
3106 ModestMailOperationPrivate *priv = NULL;
3108 helper = (RefreshAsyncHelper *) user_data;
3109 self = helper->mail_op;
3110 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3112 g_return_if_fail(priv!=NULL);
3115 priv->error = g_error_copy (error);
3116 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3121 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3122 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3123 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3124 _("Error trying to refresh the contents of %s"),
3125 tny_folder_get_name (folder));
3129 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3132 /* Call user defined callback, if it exists */
3133 if (helper->user_callback) {
3135 /* This is not a GDK lock because we are a Tinymail callback and
3136 * Tinymail already acquires the Gdk lock */
3137 helper->user_callback (self, folder, helper->user_data);
3141 g_slice_free (RefreshAsyncHelper, helper);
3143 /* Notify about operation end */
3144 modest_mail_operation_notify_end (self);
3145 g_object_unref(self);
3149 on_refresh_folder_status_update (GObject *obj,
3153 RefreshAsyncHelper *helper = NULL;
3154 ModestMailOperation *self = NULL;
3155 ModestMailOperationPrivate *priv = NULL;
3156 ModestMailOperationState *state;
3158 g_return_if_fail (user_data != NULL);
3159 g_return_if_fail (status != NULL);
3161 /* Show only the status information we want */
3162 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3165 helper = (RefreshAsyncHelper *) user_data;
3166 self = helper->mail_op;
3167 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3171 priv->done = status->position;
3172 priv->total = status->of_total;
3174 state = modest_mail_operation_clone_state (self);
3176 /* This is not a GDK lock because we are a Tinymail callback and
3177 * Tinymail already acquires the Gdk lock */
3178 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3180 g_slice_free (ModestMailOperationState, state);
3184 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3186 RefreshAsyncUserCallback user_callback,
3189 ModestMailOperationPrivate *priv = NULL;
3190 RefreshAsyncHelper *helper = NULL;
3192 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3194 /* Check memory low */
3195 if (_check_memory_low (self)) {
3197 user_callback (self, folder, user_data);
3198 /* Notify about operation end */
3199 modest_mail_operation_notify_end (self);
3203 /* Get account and set it into mail_operation */
3204 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3205 priv->account = modest_tny_folder_get_account (folder);
3206 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3208 /* Create the helper */
3209 helper = g_slice_new0 (RefreshAsyncHelper);
3210 helper->mail_op = g_object_ref(self);
3211 helper->user_callback = user_callback;
3212 helper->user_data = user_data;
3214 modest_mail_operation_notify_start (self);
3216 /* notify that the operation was started */
3217 ModestMailOperationState *state;
3218 state = modest_mail_operation_clone_state (self);
3221 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3223 g_slice_free (ModestMailOperationState, state);
3225 tny_folder_refresh_async (folder,
3227 on_refresh_folder_status_update,
3232 run_queue_stop (ModestTnySendQueue *queue,
3233 ModestMailOperation *self)
3235 ModestMailOperationPrivate *priv;
3237 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3238 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3239 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3241 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3243 modest_mail_operation_notify_end (self);
3244 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3245 g_object_unref (self);
3249 modest_mail_operation_run_queue (ModestMailOperation *self,
3250 ModestTnySendQueue *queue)
3252 ModestMailOperationPrivate *priv;
3254 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3255 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3258 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3259 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3260 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3262 modest_mail_operation_notify_start (self);
3263 g_object_ref (self);
3264 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3268 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3270 ModestMailOperation *self = (ModestMailOperation *) userdata;
3271 ModestMailOperationPrivate *priv;
3273 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3274 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3275 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3277 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3279 modest_mail_operation_notify_end (self);
3280 g_object_unref (self);
3284 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3286 ModestMailOperationPrivate *priv;
3288 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3289 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3290 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3292 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3294 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3295 priv->account = NULL;
3296 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3298 modest_mail_operation_notify_start (self);
3299 g_object_ref (self);
3300 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3304 sync_folder_finish_callback (TnyFolder *self,
3310 ModestMailOperation *mail_op;
3311 ModestMailOperationPrivate *priv;
3313 mail_op = (ModestMailOperation *) user_data;
3314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3316 /* If canceled by the user, ignore the error given by Tinymail */
3318 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3320 /* If the operation was a sync then the status is
3321 failed, but if it's part of another operation then
3322 just set it as finished with errors */
3323 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3324 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3326 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3327 priv->error = g_error_copy ((const GError *) err);
3328 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3330 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3333 modest_mail_operation_notify_end (mail_op);
3334 g_object_unref (mail_op);
3338 modest_mail_operation_sync_folder (ModestMailOperation *self,
3339 TnyFolder *folder, gboolean expunge)
3341 ModestMailOperationPrivate *priv;
3343 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3344 g_return_if_fail (TNY_IS_FOLDER (folder));
3345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3347 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3348 priv->account = modest_tny_folder_get_account (folder);
3349 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3351 modest_mail_operation_notify_start (self);
3352 g_object_ref (self);
3353 tny_folder_sync_async (folder, expunge,
3354 (TnyFolderCallback) sync_folder_finish_callback,
3359 modest_mail_operation_notify_start (ModestMailOperation *self)
3361 ModestMailOperationPrivate *priv = NULL;
3363 g_return_if_fail (self);
3365 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3367 /* Ensure that all the fields are filled correctly */
3368 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3370 /* Notify the observers about the mail operation. We do not
3371 wrapp this emission because we assume that this function is
3372 always called from within the main lock */
3373 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3378 * It's used by the mail operation queue to notify the observers
3379 * attached to that signal that the operation finished. We need to use
3380 * that because tinymail does not give us the progress of a given
3381 * operation when it finishes (it directly calls the operation
3385 modest_mail_operation_notify_end (ModestMailOperation *self)
3387 ModestMailOperationPrivate *priv = NULL;
3389 g_return_if_fail (self);
3391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3393 /* Notify the observers about the mail operation end. We do
3394 not wrapp this emission because we assume that this
3395 function is always called from within the main lock */
3396 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3398 /* Remove the error user data */
3399 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3400 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3404 modest_mail_operation_get_account (ModestMailOperation *self)
3406 ModestMailOperationPrivate *priv = NULL;
3408 g_return_val_if_fail (self, NULL);
3410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3412 return (priv->account) ? g_object_ref (priv->account) : NULL;
3416 modest_mail_operation_noop (ModestMailOperation *self)
3418 ModestMailOperationPrivate *priv = NULL;
3420 g_return_if_fail (self);
3422 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3423 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3424 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3428 /* This mail operation does nothing actually */
3429 modest_mail_operation_notify_start (self);
3430 modest_mail_operation_notify_end (self);
3435 modest_mail_operation_to_string (ModestMailOperation *self)
3437 const gchar *type, *status, *account_id;
3438 ModestMailOperationPrivate *priv = NULL;
3440 g_return_val_if_fail (self, NULL);
3442 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3444 /* new operations don't have anything interesting */
3445 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3446 return g_strdup_printf ("%p <new operation>", self);
3448 switch (priv->op_type) {
3449 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3450 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3451 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3452 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3453 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3454 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3455 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3456 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3457 default: type = "UNEXPECTED"; break;
3460 switch (priv->status) {
3461 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3462 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3463 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3464 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3465 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3466 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3467 default: status= "UNEXPECTED"; break;
3470 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3472 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3473 priv->done, priv->total,
3474 priv->error && priv->error->message ? priv->error->message : "");
3478 * Once the mail operations were objects this will be no longer
3479 * needed. I don't like it, but we need it for the moment
3482 _check_memory_low (ModestMailOperation *mail_op)
3484 if (modest_platform_check_memory_low (NULL, FALSE)) {
3485 ModestMailOperationPrivate *priv;
3487 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3488 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3489 g_set_error (&(priv->error),
3490 MODEST_MAIL_OPERATION_ERROR,
3491 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3492 "Not enough memory to complete the operation");