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 /* ******************************************************************* */
634 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
640 ModestMailOperationPrivate *priv;
641 ModestMailOperation *self;
643 self = MODEST_MAIL_OPERATION (user_data);
644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
646 if (cancelled || err)
650 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
651 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
652 "Error adding a msg to the send queue\n");
653 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
655 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
658 modest_mail_operation_notify_end (self);
659 g_object_unref (self);
663 modest_mail_operation_send_mail (ModestMailOperation *self,
664 TnyTransportAccount *transport_account,
667 TnySendQueue *send_queue = NULL;
668 ModestMailOperationPrivate *priv;
670 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
671 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
672 g_return_if_fail (msg && TNY_IS_MSG (msg));
674 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
676 /* Get account and set it into mail_operation */
677 priv->account = g_object_ref (transport_account);
678 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
682 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
683 if (!TNY_IS_SEND_QUEUE(send_queue)) {
685 g_error_free (priv->error);
688 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
689 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
690 "modest: could not find send queue for account\n");
691 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
692 modest_mail_operation_notify_end (self);
694 modest_mail_operation_notify_start (self);
695 /* Add the msg to the queue. The callback will
696 finalize the mail operation */
697 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
698 NULL, g_object_ref (self));
699 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
706 idle_create_msg_cb (gpointer idle_data)
708 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
710 /* This is a GDK lock because we are an idle callback and
711 * info->callback can contain Gtk+ code */
713 gdk_threads_enter (); /* CHECKED */
714 info->callback (info->mail_op, info->msg, info->userdata);
716 g_object_unref (info->mail_op);
718 g_object_unref (info->msg);
719 g_slice_free (CreateMsgIdleInfo, info);
720 gdk_threads_leave (); /* CHECKED */
726 create_msg_thread (gpointer thread_data)
728 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
729 TnyMsg *new_msg = NULL;
730 ModestMailOperationPrivate *priv;
732 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
733 if (info->html_body == NULL) {
734 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
735 info->bcc, info->subject, info->plain_body,
736 info->attachments_list,
739 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
740 info->bcc, info->subject, info->html_body,
741 info->plain_body, info->attachments_list,
749 /* Set priority flags in message */
750 header = tny_msg_get_header (new_msg);
751 tny_header_set_flag (header, info->priority_flags);
753 /* Set attachment flags in message */
754 if (info->attachments_list != NULL)
755 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
757 g_object_unref (G_OBJECT(header));
759 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
761 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
762 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
763 "modest: failed to create a new msg\n");
771 g_free (info->plain_body);
772 g_free (info->html_body);
773 g_free (info->subject);
774 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
775 g_list_free (info->attachments_list);
776 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
777 g_list_free (info->images_list);
779 if (info->callback) {
780 CreateMsgIdleInfo *idle_info;
781 idle_info = g_slice_new0 (CreateMsgIdleInfo);
782 idle_info->mail_op = g_object_ref (info->mail_op);
783 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
784 idle_info->callback = info->callback;
785 idle_info->userdata = info->userdata;
786 g_idle_add (idle_create_msg_cb, idle_info);
788 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
791 g_object_unref (info->mail_op);
792 g_slice_free (CreateMsgInfo, info);
793 if (new_msg) g_object_unref(new_msg);
799 modest_mail_operation_create_msg (ModestMailOperation *self,
800 const gchar *from, const gchar *to,
801 const gchar *cc, const gchar *bcc,
802 const gchar *subject, const gchar *plain_body,
803 const gchar *html_body,
804 const GList *attachments_list,
805 const GList *images_list,
806 TnyHeaderFlags priority_flags,
807 ModestMailOperationCreateMsgCallback callback,
810 CreateMsgInfo *info = NULL;
812 info = g_slice_new0 (CreateMsgInfo);
813 info->mail_op = g_object_ref (self);
815 info->from = g_strdup (from);
816 info->to = g_strdup (to);
817 info->cc = g_strdup (cc);
818 info->bcc = g_strdup (bcc);
819 info->subject = g_strdup (subject);
820 info->plain_body = g_strdup (plain_body);
821 info->html_body = g_strdup (html_body);
822 info->attachments_list = g_list_copy ((GList *) attachments_list);
823 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
824 info->images_list = g_list_copy ((GList *) images_list);
825 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
826 info->priority_flags = priority_flags;
828 info->callback = callback;
829 info->userdata = userdata;
831 g_thread_create (create_msg_thread, info, FALSE, NULL);
836 TnyTransportAccount *transport_account;
841 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
845 ModestMailOperationPrivate *priv = NULL;
846 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
847 TnyFolder *draft_folder = NULL;
848 TnyFolder *outbox_folder = NULL;
849 TnyHeader *header = NULL;
851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
854 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
855 modest_mail_operation_notify_end (self);
859 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
860 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
861 modest_mail_operation_notify_end (self);
865 /* Call mail operation */
866 modest_mail_operation_send_mail (self, info->transport_account, msg);
868 if (info->draft_msg != NULL) {
869 TnyList *tmp_headers = NULL;
870 TnyFolder *folder = NULL;
871 TnyFolder *src_folder = NULL;
872 TnyFolderType folder_type;
873 TnyTransportAccount *transport_account = NULL;
875 /* To remove the old mail from its source folder, we need to get the
876 * transport account of the original draft message (the transport account
877 * might have been changed by the user) */
878 header = tny_msg_get_header (info->draft_msg);
879 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
880 modest_runtime_get_account_store(), header);
881 if (transport_account == NULL)
882 transport_account = g_object_ref(info->transport_account);
883 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
884 TNY_FOLDER_TYPE_DRAFTS);
885 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
886 TNY_FOLDER_TYPE_OUTBOX);
887 g_object_unref(transport_account);
890 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
894 if (!outbox_folder) {
895 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
900 folder = tny_msg_get_folder (info->draft_msg);
901 if (folder == NULL) goto end;
902 folder_type = modest_tny_folder_guess_folder_type (folder);
904 if (folder_type == TNY_FOLDER_TYPE_INVALID)
905 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
907 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
908 src_folder = outbox_folder;
910 src_folder = draft_folder;
912 /* Note: This can fail (with a warning) if the message is not really already in a folder,
913 * because this function requires it to have a UID. */
914 tmp_headers = tny_simple_list_new ();
915 tny_list_append (tmp_headers, (GObject*) header);
916 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
917 g_object_unref (tmp_headers);
918 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
920 g_object_unref (folder);
925 g_object_unref (header);
927 g_object_unref (info->draft_msg);
929 g_object_unref (draft_folder);
931 g_object_unref (outbox_folder);
932 if (info->transport_account)
933 g_object_unref (info->transport_account);
934 g_slice_free (SendNewMailInfo, info);
938 modest_mail_operation_send_new_mail (ModestMailOperation *self,
939 TnyTransportAccount *transport_account,
941 const gchar *from, const gchar *to,
942 const gchar *cc, const gchar *bcc,
943 const gchar *subject, const gchar *plain_body,
944 const gchar *html_body,
945 const GList *attachments_list,
946 const GList *images_list,
947 TnyHeaderFlags priority_flags)
949 ModestMailOperationPrivate *priv = NULL;
950 SendNewMailInfo *info;
952 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
953 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
955 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
956 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
957 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
958 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
960 /* Check parametters */
962 /* Set status failed and set an error */
963 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
964 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
965 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
966 _("Error trying to send a mail. You need to set at least one recipient"));
969 info = g_slice_new0 (SendNewMailInfo);
970 info->transport_account = transport_account;
971 if (transport_account)
972 g_object_ref (transport_account);
973 info->draft_msg = draft_msg;
975 g_object_ref (draft_msg);
978 modest_mail_operation_notify_start (self);
979 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
980 attachments_list, images_list, priority_flags,
981 modest_mail_operation_send_new_mail_cb, info);
987 TnyTransportAccount *transport_account;
989 SaveToDraftstCallback callback;
993 ModestMailOperation *mailop;
994 } SaveToDraftsAddMsgInfo;
997 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1002 ModestMailOperationPrivate *priv = NULL;
1003 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1004 GError *io_error = NULL;
1006 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1008 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1009 io_error = priv->error;
1013 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1014 g_error_free(priv->error);
1017 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1019 if ((!priv->error) && (info->draft_msg != NULL)) {
1020 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1021 TnyFolder *src_folder = tny_header_get_folder (header);
1023 /* Remove the old draft */
1024 tny_folder_remove_msg (src_folder, header, NULL);
1026 /* Synchronize to expunge and to update the msg counts */
1027 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1028 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1030 g_object_unref (G_OBJECT(header));
1031 g_object_unref (G_OBJECT(src_folder));
1035 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1037 g_error_free (io_error);
1040 } else if (io_error) {
1041 priv->error = io_error;
1042 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1044 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1047 /* Call the user callback */
1049 info->callback (info->mailop, info->msg, info->user_data);
1051 if (info->transport_account)
1052 g_object_unref (G_OBJECT(info->transport_account));
1053 if (info->draft_msg)
1054 g_object_unref (G_OBJECT (info->draft_msg));
1056 g_object_unref (G_OBJECT(info->drafts));
1058 g_object_unref (G_OBJECT (info->msg));
1060 modest_mail_operation_notify_end (info->mailop);
1061 g_object_unref(info->mailop);
1062 g_slice_free (SaveToDraftsAddMsgInfo, info);
1067 TnyTransportAccount *transport_account;
1069 SaveToDraftstCallback callback;
1074 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1078 TnyFolder *drafts = NULL;
1079 ModestMailOperationPrivate *priv = NULL;
1080 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1082 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1085 if (!(priv->error)) {
1086 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1087 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1088 "modest: failed to create a new msg\n");
1091 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1092 TNY_FOLDER_TYPE_DRAFTS);
1093 if (!drafts && !(priv->error)) {
1094 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1095 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1096 "modest: failed to create a new msg\n");
1100 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1101 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1102 cb_info->transport_account = g_object_ref(info->transport_account);
1103 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1104 cb_info->callback = info->callback;
1105 cb_info->user_data = info->user_data;
1106 cb_info->drafts = g_object_ref(drafts);
1107 cb_info->msg = g_object_ref(msg);
1108 cb_info->mailop = g_object_ref(self);
1109 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1112 /* Call the user callback */
1113 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1115 info->callback (self, msg, info->user_data);
1116 modest_mail_operation_notify_end (self);
1120 g_object_unref (G_OBJECT(drafts));
1121 if (info->draft_msg)
1122 g_object_unref (G_OBJECT (info->draft_msg));
1123 if (info->transport_account)
1124 g_object_unref (G_OBJECT(info->transport_account));
1125 g_slice_free (SaveToDraftsInfo, info);
1129 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1130 TnyTransportAccount *transport_account,
1132 const gchar *from, const gchar *to,
1133 const gchar *cc, const gchar *bcc,
1134 const gchar *subject, const gchar *plain_body,
1135 const gchar *html_body,
1136 const GList *attachments_list,
1137 const GList *images_list,
1138 TnyHeaderFlags priority_flags,
1139 SaveToDraftstCallback callback,
1142 ModestMailOperationPrivate *priv = NULL;
1143 SaveToDraftsInfo *info = NULL;
1145 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1146 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1148 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1150 /* Get account and set it into mail_operation */
1151 priv->account = g_object_ref (transport_account);
1152 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1154 info = g_slice_new0 (SaveToDraftsInfo);
1155 info->transport_account = g_object_ref (transport_account);
1156 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1157 info->callback = callback;
1158 info->user_data = user_data;
1160 modest_mail_operation_notify_start (self);
1161 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1162 attachments_list, images_list, priority_flags,
1163 modest_mail_operation_save_to_drafts_cb, info);
1168 ModestMailOperation *mail_op;
1169 TnyMimePart *mime_part;
1171 GetMimePartSizeCallback callback;
1173 } GetMimePartSizeInfo;
1175 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1176 /* We use this folder observer to track the headers that have been
1177 * added to a folder */
1180 TnyList *new_headers;
1181 } InternalFolderObserver;
1184 GObjectClass parent;
1185 } InternalFolderObserverClass;
1187 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1189 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1190 internal_folder_observer,
1192 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1196 foreach_add_item (gpointer header, gpointer user_data)
1198 tny_list_prepend (TNY_LIST (user_data),
1199 g_object_ref (G_OBJECT (header)));
1202 /* This is the method that looks for new messages in a folder */
1204 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1206 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1208 TnyFolderChangeChanged changed;
1210 changed = tny_folder_change_get_changed (change);
1212 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1215 /* Get added headers */
1216 list = tny_simple_list_new ();
1217 tny_folder_change_get_added_headers (change, list);
1219 /* Add them to the folder observer */
1220 tny_list_foreach (list, foreach_add_item,
1221 derived->new_headers);
1223 g_object_unref (G_OBJECT (list));
1228 internal_folder_observer_init (InternalFolderObserver *self)
1230 self->new_headers = tny_simple_list_new ();
1233 internal_folder_observer_finalize (GObject *object)
1235 InternalFolderObserver *self;
1237 self = (InternalFolderObserver *) object;
1238 g_object_unref (self->new_headers);
1240 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1243 tny_folder_observer_init (TnyFolderObserverIface *iface)
1245 iface->update = internal_folder_observer_update;
1248 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1250 GObjectClass *object_class;
1252 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1253 object_class = (GObjectClass*) klass;
1254 object_class->finalize = internal_folder_observer_finalize;
1258 destroy_update_account_info (UpdateAccountInfo *info)
1260 g_free (info->account_name);
1261 g_object_unref (info->folders);
1262 g_object_unref (info->mail_op);
1263 g_slice_free (UpdateAccountInfo, info);
1268 update_account_send_mail (UpdateAccountInfo *info)
1270 TnyTransportAccount *transport_account = NULL;
1272 /* Get the transport account */
1273 transport_account = (TnyTransportAccount *)
1274 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1275 info->account_name);
1277 if (transport_account) {
1278 ModestTnySendQueue *send_queue;
1282 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1283 g_object_unref (transport_account);
1285 if (TNY_IS_SEND_QUEUE (send_queue)) {
1286 /* Get outbox folder */
1287 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1288 if (outbox) { /* this could fail in some cases */
1289 num_messages = tny_folder_get_all_count (outbox);
1290 g_object_unref (outbox);
1292 g_warning ("%s: could not get outbox", __FUNCTION__);
1296 if (num_messages != 0) {
1297 /* Reenable suspended items */
1298 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1301 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1302 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1310 update_account_get_msg_async_cb (TnyFolder *folder,
1316 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1317 ModestMailOperationPrivate *priv;
1319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1322 if (TNY_IS_MSG (msg)) {
1323 TnyHeader *header = tny_msg_get_header (msg);
1326 ModestMailOperationState *state;
1327 state = modest_mail_operation_clone_state (msg_info->mail_op);
1328 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1329 state->bytes_done = msg_info->sum_total_bytes;
1330 state->bytes_total = msg_info->total_bytes;
1332 /* Notify the status change. Only notify about changes
1333 referred to bytes */
1334 g_signal_emit (G_OBJECT (msg_info->mail_op),
1335 signals[PROGRESS_CHANGED_SIGNAL],
1338 g_object_unref (header);
1339 g_slice_free (ModestMailOperationState, state);
1343 if (priv->done == priv->total) {
1344 TnyList *new_headers;
1345 UpdateAccountInfo *info;
1347 /* After getting all the messages send the ones in the
1349 info = (UpdateAccountInfo *) msg_info->user_data;
1350 update_account_send_mail (info);
1352 /* Check if the operation was a success */
1354 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1356 /* Call the user callback and free */
1357 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1358 update_account_notify_user_and_free (info, new_headers);
1359 g_object_unref (new_headers);
1361 /* Delete the helper */
1362 g_object_unref (msg_info->more_msgs);
1363 g_object_unref (msg_info->mail_op);
1364 g_slice_free (GetMsgInfo, msg_info);
1369 update_account_notify_user_and_free (UpdateAccountInfo *info,
1370 TnyList *new_headers)
1372 /* Set the account back to not busy */
1373 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1374 info->account_name, FALSE);
1378 info->callback (info->mail_op, new_headers, info->user_data);
1380 /* Mail operation end */
1381 modest_mail_operation_notify_end (info->mail_op);
1385 g_object_unref (new_headers);
1386 destroy_update_account_info (info);
1390 inbox_refreshed_cb (TnyFolder *inbox,
1395 UpdateAccountInfo *info;
1396 ModestMailOperationPrivate *priv;
1397 TnyIterator *new_headers_iter;
1398 GPtrArray *new_headers_array = NULL;
1399 gint max_size, retrieve_limit, i;
1400 ModestAccountMgr *mgr;
1401 ModestAccountRetrieveType retrieve_type;
1402 TnyList *new_headers = NULL;
1403 gboolean headers_only, ignore_limit;
1405 info = (UpdateAccountInfo *) user_data;
1406 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1407 mgr = modest_runtime_get_account_mgr ();
1409 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1410 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1412 if (canceled || err) {
1413 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1415 priv->error = g_error_copy (err);
1417 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1418 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1421 tny_folder_remove_observer (inbox, info->inbox_observer);
1422 g_object_unref (info->inbox_observer);
1423 info->inbox_observer = NULL;
1425 /* Notify the user about the error and then exit */
1426 update_account_notify_user_and_free (info, NULL);
1431 /* Try to send anyway */
1435 /* Get the message max size */
1436 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1437 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1439 max_size = G_MAXINT;
1441 max_size = max_size * KB;
1443 /* Create the new headers array. We need it to sort the
1444 new headers by date */
1445 new_headers_array = g_ptr_array_new ();
1446 if (info->inbox_observer) {
1447 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1448 while (!tny_iterator_is_done (new_headers_iter)) {
1449 TnyHeader *header = NULL;
1451 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1452 /* Apply per-message size limits */
1453 if (tny_header_get_message_size (header) < max_size)
1454 g_ptr_array_add (new_headers_array, g_object_ref (header));
1456 g_object_unref (header);
1457 tny_iterator_next (new_headers_iter);
1459 g_object_unref (new_headers_iter);
1461 tny_folder_remove_observer (inbox, info->inbox_observer);
1462 g_object_unref (info->inbox_observer);
1463 info->inbox_observer = NULL;
1466 if (new_headers_array->len == 0) {
1467 g_ptr_array_free (new_headers_array, FALSE);
1471 /* Get per-account message amount retrieval limit */
1472 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1473 if (retrieve_limit == 0)
1474 retrieve_limit = G_MAXINT;
1476 /* Get per-account retrieval type */
1477 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1478 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1481 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1483 /* Ask the users if they want to retrieve all the messages
1484 even though the limit was exceeded */
1485 ignore_limit = FALSE;
1486 if (new_headers_array->len > retrieve_limit) {
1487 /* Ask the user if a callback has been specified and
1488 if the mail operation has a source (this means that
1489 was invoked by the user and not automatically by a
1491 if (info->retrieve_all_cb && priv->source)
1492 ignore_limit = info->retrieve_all_cb (priv->source,
1493 new_headers_array->len,
1497 /* Copy the headers to a list and free the array */
1498 new_headers = tny_simple_list_new ();
1499 for (i=0; i < new_headers_array->len; i++) {
1500 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1501 tny_list_append (new_headers, G_OBJECT (header));
1503 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1504 g_ptr_array_free (new_headers_array, FALSE);
1506 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1509 GetMsgInfo *msg_info;
1513 priv->total = tny_list_get_length (new_headers);
1515 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1517 iter = tny_list_create_iterator (new_headers);
1519 /* Create the message info */
1520 msg_info = g_slice_new0 (GetMsgInfo);
1521 msg_info->mail_op = g_object_ref (info->mail_op);
1522 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1523 msg_info->more_msgs = g_object_ref (iter);
1524 msg_info->user_data = info;
1526 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1527 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1528 TnyFolder *folder = tny_header_get_folder (header);
1530 /* Get message in an async way */
1531 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1534 g_object_unref (folder);
1537 tny_iterator_next (iter);
1539 g_object_unref (iter);
1541 /* The mail operation will finish when the last
1542 message is retrieved */
1546 /* If we don't have to retrieve the new messages then
1548 update_account_send_mail (info);
1550 /* Check if the operation was a success */
1552 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1554 /* Call the user callback and free */
1555 update_account_notify_user_and_free (info, new_headers);
1559 inbox_refresh_status_update (GObject *obj,
1563 UpdateAccountInfo *info = NULL;
1564 ModestMailOperation *self = NULL;
1565 ModestMailOperationPrivate *priv = NULL;
1566 ModestMailOperationState *state;
1568 g_return_if_fail (user_data != NULL);
1569 g_return_if_fail (status != NULL);
1571 /* Show only the status information we want */
1572 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1575 info = (UpdateAccountInfo *) user_data;
1576 self = info->mail_op;
1577 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1579 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1581 priv->done = status->position;
1582 priv->total = status->of_total;
1584 state = modest_mail_operation_clone_state (self);
1586 /* This is not a GDK lock because we are a Tinymail callback and
1587 * Tinymail already acquires the Gdk lock */
1588 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1590 g_slice_free (ModestMailOperationState, state);
1594 recurse_folders_async_cb (TnyFolderStore *folder_store,
1600 UpdateAccountInfo *info;
1601 ModestMailOperationPrivate *priv;
1603 info = (UpdateAccountInfo *) user_data;
1604 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1606 if (err || canceled) {
1607 /* If the error was previosly set by another callback
1608 don't set it again */
1610 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1612 priv->error = g_error_copy (err);
1614 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1615 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1619 /* We're not getting INBOX children if we don't want to poke all */
1620 TnyIterator *iter = tny_list_create_iterator (list);
1621 while (!tny_iterator_is_done (iter)) {
1622 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1624 /* Add to the list of all folders */
1625 tny_list_append (info->folders, (GObject *) folder);
1627 if (info->poke_all) {
1628 TnyList *folders = tny_simple_list_new ();
1629 /* Add pending call */
1630 info->pending_calls++;
1632 tny_folder_store_get_folders_async (folder, folders, NULL,
1633 recurse_folders_async_cb,
1635 g_object_unref (folders);
1638 g_object_unref (G_OBJECT (folder));
1640 tny_iterator_next (iter);
1642 g_object_unref (G_OBJECT (iter));
1645 /* Remove my own pending call */
1646 info->pending_calls--;
1648 /* This means that we have all the folders */
1649 if (info->pending_calls == 0) {
1650 TnyIterator *iter_all_folders;
1651 TnyFolder *inbox = NULL;
1653 /* If there was any error do not continue */
1655 update_account_notify_user_and_free (info, NULL);
1659 iter_all_folders = tny_list_create_iterator (info->folders);
1661 /* Do a poke status over all folders */
1662 while (!tny_iterator_is_done (iter_all_folders) &&
1663 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1664 TnyFolder *folder = NULL;
1666 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1668 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1669 /* Get a reference to the INBOX */
1670 inbox = g_object_ref (folder);
1672 /* Issue a poke status over the folder */
1674 tny_folder_poke_status (folder);
1677 /* Free and go to next */
1678 g_object_unref (folder);
1679 tny_iterator_next (iter_all_folders);
1681 g_object_unref (iter_all_folders);
1683 /* Refresh the INBOX */
1685 /* Refresh the folder. Our observer receives
1686 * the new emails during folder refreshes, so
1687 * we can use observer->new_headers
1689 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1690 tny_folder_add_observer (inbox, info->inbox_observer);
1692 /* Refresh the INBOX */
1693 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1694 g_object_unref (inbox);
1696 /* We could not perform the inbox refresh but
1697 we'll try to send mails anyway */
1698 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1704 modest_mail_operation_update_account (ModestMailOperation *self,
1705 const gchar *account_name,
1707 gboolean interactive,
1708 RetrieveAllCallback retrieve_all_cb,
1709 UpdateAccountCallback callback,
1712 UpdateAccountInfo *info = NULL;
1713 ModestMailOperationPrivate *priv = NULL;
1714 ModestTnyAccountStore *account_store = NULL;
1716 ModestMailOperationState *state;
1718 /* Init mail operation */
1719 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1722 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1723 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1725 /* Get the store account */
1726 account_store = modest_runtime_get_account_store ();
1728 modest_tny_account_store_get_server_account (account_store,
1730 TNY_ACCOUNT_TYPE_STORE);
1732 /* The above function could return NULL */
1733 if (!priv->account) {
1734 /* Check if the operation was a success */
1735 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1736 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1738 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1740 /* Call the user callback */
1742 callback (self, NULL, user_data);
1744 /* Notify about operation end */
1745 modest_mail_operation_notify_end (self);
1750 /* We have once seen priv->account getting finalized during this code,
1751 * therefore adding a reference (bug #82296) */
1753 g_object_ref (priv->account);
1755 /* Create the helper object */
1756 info = g_slice_new0 (UpdateAccountInfo);
1757 info->pending_calls = 1;
1758 info->folders = tny_simple_list_new ();
1759 info->mail_op = g_object_ref (self);
1760 info->poke_all = poke_all;
1761 info->interactive = interactive;
1762 info->account_name = g_strdup (account_name);
1763 info->callback = callback;
1764 info->user_data = user_data;
1765 info->retrieve_all_cb = retrieve_all_cb;
1767 /* Set account busy */
1768 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1769 modest_mail_operation_notify_start (self);
1771 /* notify about the start of the operation */
1772 state = modest_mail_operation_clone_state (self);
1776 /* Start notifying progress */
1777 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1778 g_slice_free (ModestMailOperationState, state);
1780 /* Get all folders and continue in the callback */
1781 folders = tny_simple_list_new ();
1782 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1784 recurse_folders_async_cb,
1786 g_object_unref (folders);
1788 g_object_unref (priv->account);
1793 * Used to notify the queue from the main
1794 * loop. We call it inside an idle call to achieve that
1797 idle_notify_queue (gpointer data)
1799 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1801 gdk_threads_enter ();
1802 modest_mail_operation_notify_end (mail_op);
1803 gdk_threads_leave ();
1804 g_object_unref (mail_op);
1810 compare_headers_by_date (gconstpointer a,
1813 TnyHeader **header1, **header2;
1814 time_t sent1, sent2;
1816 header1 = (TnyHeader **) a;
1817 header2 = (TnyHeader **) b;
1819 sent1 = tny_header_get_date_sent (*header1);
1820 sent2 = tny_header_get_date_sent (*header2);
1822 /* We want the most recent ones (greater time_t) at the
1831 /* ******************************************************************* */
1832 /* ************************** STORE ACTIONS ************************* */
1833 /* ******************************************************************* */
1836 ModestMailOperation *mail_op;
1837 CreateFolderUserCallback callback;
1843 create_folder_cb (TnyFolderStore *parent_folder,
1845 TnyFolder *new_folder,
1849 ModestMailOperationPrivate *priv;
1850 CreateFolderInfo *info;
1852 info = (CreateFolderInfo *) user_data;
1853 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1855 if (canceled || err) {
1856 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1858 priv->error = g_error_copy (err);
1860 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1861 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1864 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1867 /* The user will unref the new_folder */
1869 info->callback (info->mail_op, parent_folder,
1870 new_folder, info->user_data);
1872 /* Notify about operation end */
1873 modest_mail_operation_notify_end (info->mail_op);
1876 g_object_unref (info->mail_op);
1877 g_slice_free (CreateFolderInfo, info);
1881 modest_mail_operation_create_folder (ModestMailOperation *self,
1882 TnyFolderStore *parent,
1884 CreateFolderUserCallback callback,
1887 ModestMailOperationPrivate *priv;
1889 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1890 g_return_if_fail (name);
1892 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1893 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1894 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1895 g_object_ref (parent) :
1896 modest_tny_folder_get_account (TNY_FOLDER (parent));
1898 /* Check for already existing folder */
1899 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1900 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1901 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1902 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1903 _CS("ckdg_ib_folder_already_exists"));
1907 if (TNY_IS_FOLDER (parent)) {
1908 /* Check folder rules */
1909 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1910 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1911 /* Set status failed and set an error */
1912 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1913 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1914 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1915 _("mail_in_ui_folder_create_error"));
1919 if (!strcmp (name, " ") || strchr (name, '/')) {
1920 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1921 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1922 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1923 _("mail_in_ui_folder_create_error"));
1927 CreateFolderInfo *info;
1929 info = g_slice_new0 (CreateFolderInfo);
1930 info->mail_op = g_object_ref (self);
1931 info->callback = callback;
1932 info->user_data = user_data;
1934 modest_mail_operation_notify_start (self);
1936 /* Create the folder */
1937 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1940 /* Call the user callback anyway */
1942 callback (self, parent, NULL, user_data);
1943 /* Notify about operation end */
1944 modest_mail_operation_notify_end (self);
1949 modest_mail_operation_remove_folder (ModestMailOperation *self,
1951 gboolean remove_to_trash)
1953 ModestMailOperationPrivate *priv;
1954 ModestTnyFolderRules rules;
1956 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1957 g_return_if_fail (TNY_IS_FOLDER (folder));
1959 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1961 /* Check folder rules */
1962 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1963 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1964 /* Set status failed and set an error */
1965 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1966 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1967 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1968 _("mail_in_ui_folder_delete_error"));
1972 /* Get the account */
1973 priv->account = modest_tny_folder_get_account (folder);
1974 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1976 /* Delete folder or move to trash */
1977 if (remove_to_trash) {
1978 TnyFolder *trash_folder = NULL;
1979 trash_folder = modest_tny_account_get_special_folder (priv->account,
1980 TNY_FOLDER_TYPE_TRASH);
1981 /* TODO: error_handling */
1983 modest_mail_operation_notify_start (self);
1984 modest_mail_operation_xfer_folder (self, folder,
1985 TNY_FOLDER_STORE (trash_folder),
1987 g_object_unref (trash_folder);
1989 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1992 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1994 modest_mail_operation_notify_start (self);
1995 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1996 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2001 g_object_unref (parent);
2003 g_warning ("%s: could not get parent folder", __FUNCTION__);
2007 /* Notify about operation end */
2008 modest_mail_operation_notify_end (self);
2012 transfer_folder_status_cb (GObject *obj,
2016 ModestMailOperation *self;
2017 ModestMailOperationPrivate *priv;
2018 ModestMailOperationState *state;
2019 XFerFolderAsyncHelper *helper;
2021 g_return_if_fail (status != NULL);
2023 /* Show only the status information we want */
2024 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2027 helper = (XFerFolderAsyncHelper *) user_data;
2028 g_return_if_fail (helper != NULL);
2030 self = helper->mail_op;
2031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2033 priv->done = status->position;
2034 priv->total = status->of_total;
2036 state = modest_mail_operation_clone_state (self);
2038 /* This is not a GDK lock because we are a Tinymail callback
2039 * which is already GDK locked by Tinymail */
2041 /* no gdk_threads_enter (), CHECKED */
2043 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2045 /* no gdk_threads_leave (), CHECKED */
2047 g_slice_free (ModestMailOperationState, state);
2052 transfer_folder_cb (TnyFolder *folder,
2054 TnyFolderStore *into,
2055 TnyFolder *new_folder,
2059 XFerFolderAsyncHelper *helper;
2060 ModestMailOperation *self = NULL;
2061 ModestMailOperationPrivate *priv = NULL;
2063 helper = (XFerFolderAsyncHelper *) user_data;
2064 g_return_if_fail (helper != NULL);
2066 self = helper->mail_op;
2067 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2070 priv->error = g_error_copy (err);
2072 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2073 } else if (cancelled) {
2074 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2075 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2076 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2077 _("Transference of %s was cancelled."),
2078 tny_folder_get_name (folder));
2081 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2084 /* Notify about operation end */
2085 modest_mail_operation_notify_end (self);
2087 /* If user defined callback function was defined, call it */
2088 if (helper->user_callback) {
2090 /* This is not a GDK lock because we are a Tinymail callback
2091 * which is already GDK locked by Tinymail */
2093 /* no gdk_threads_enter (), CHECKED */
2094 helper->user_callback (self, new_folder, helper->user_data);
2095 /* no gdk_threads_leave () , CHECKED */
2099 g_object_unref (helper->mail_op);
2100 g_slice_free (XFerFolderAsyncHelper, helper);
2105 * This function checks if the new name is a valid name for our local
2106 * folders account. The new name could not be the same than then name
2107 * of any of the mandatory local folders
2109 * We can not rely on tinymail because tinymail does not check the
2110 * name of the virtual folders that the account could have in the case
2111 * that we're doing a rename (because it directly calls Camel which
2112 * knows nothing about our virtual folders).
2114 * In the case of an actual copy/move (i.e. move/copy a folder between
2115 * accounts) tinymail uses the tny_folder_store_create_account which
2116 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2117 * checks the new name of the folder, so this call in that case
2118 * wouldn't be needed. *But* NOTE that if tinymail changes its
2119 * implementation (if folder transfers within the same account is no
2120 * longer implemented as a rename) this call will allow Modest to work
2123 * If the new name is not valid, this function will set the status to
2124 * failed and will set also an error in the mail operation
2127 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2128 TnyFolderStore *into,
2129 const gchar *new_name)
2131 if (TNY_IS_ACCOUNT (into) &&
2132 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2133 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2135 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2136 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2137 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2138 _CS("ckdg_ib_folder_already_exists"));
2145 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2147 TnyFolderStore *parent,
2148 gboolean delete_original,
2149 XferFolderAsyncUserCallback user_callback,
2152 ModestMailOperationPrivate *priv = NULL;
2153 ModestTnyFolderRules parent_rules = 0, rules;
2154 XFerFolderAsyncHelper *helper = NULL;
2155 const gchar *folder_name = NULL;
2156 const gchar *error_msg;
2158 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2159 g_return_if_fail (TNY_IS_FOLDER (folder));
2160 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2162 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2163 folder_name = tny_folder_get_name (folder);
2165 /* Set the error msg */
2166 error_msg = _("mail_in_ui_folder_move_target_error");
2168 /* Get account and set it into mail_operation */
2169 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2170 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2171 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2173 /* Get folder rules */
2174 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2175 if (TNY_IS_FOLDER (parent))
2176 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2178 /* Apply operation constraints */
2179 if ((gpointer) parent == (gpointer) folder ||
2180 (!TNY_IS_FOLDER_STORE (parent)) ||
2181 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2184 } else if (TNY_IS_FOLDER (parent) &&
2185 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2189 } else if (TNY_IS_FOLDER (parent) &&
2190 TNY_IS_FOLDER_STORE (folder) &&
2191 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2192 TNY_FOLDER_STORE (folder))) {
2193 /* Do not move a parent into a child */
2195 } else if (TNY_IS_FOLDER_STORE (parent) &&
2196 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2197 /* Check that the new folder name is not used by any
2200 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2201 /* Check that the new folder name is not used by any
2202 special local folder */
2205 /* Create the helper */
2206 helper = g_slice_new0 (XFerFolderAsyncHelper);
2207 helper->mail_op = g_object_ref (self);
2208 helper->user_callback = user_callback;
2209 helper->user_data = user_data;
2211 /* Move/Copy folder */
2212 modest_mail_operation_notify_start (self);
2213 tny_folder_copy_async (folder,
2215 tny_folder_get_name (folder),
2218 transfer_folder_status_cb,
2224 /* Set status failed and set an error */
2225 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2226 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2227 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2230 /* Call the user callback if exists */
2232 user_callback (self, NULL, user_data);
2234 /* Notify the queue */
2235 modest_mail_operation_notify_end (self);
2239 modest_mail_operation_rename_folder (ModestMailOperation *self,
2242 XferFolderAsyncUserCallback user_callback,
2245 ModestMailOperationPrivate *priv;
2246 ModestTnyFolderRules rules;
2247 XFerFolderAsyncHelper *helper;
2249 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2250 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2251 g_return_if_fail (name);
2253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2255 /* Get account and set it into mail_operation */
2256 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2257 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2259 /* Check folder rules */
2260 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2261 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2263 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2266 TnyFolderStore *into;
2268 into = tny_folder_get_folder_store (folder);
2270 /* Check that the new folder name is not used by any
2271 special local folder */
2272 if (new_name_valid_if_local_account (priv, into, name)) {
2273 /* Create the helper */
2274 helper = g_slice_new0 (XFerFolderAsyncHelper);
2275 helper->mail_op = g_object_ref(self);
2276 helper->user_callback = user_callback;
2277 helper->user_data = user_data;
2279 /* Rename. Camel handles folder subscription/unsubscription */
2280 modest_mail_operation_notify_start (self);
2281 tny_folder_copy_async (folder, into, name, TRUE,
2283 transfer_folder_status_cb,
2285 g_object_unref (into);
2287 g_object_unref (into);
2294 /* Set status failed and set an error */
2295 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2296 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2297 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2298 _("FIXME: unable to rename"));
2301 user_callback (self, NULL, user_data);
2303 /* Notify about operation end */
2304 modest_mail_operation_notify_end (self);
2307 /* ******************************************************************* */
2308 /* ************************** MSG ACTIONS ************************* */
2309 /* ******************************************************************* */
2312 modest_mail_operation_get_msg (ModestMailOperation *self,
2314 gboolean progress_feedback,
2315 GetMsgAsyncUserCallback user_callback,
2318 GetMsgInfo *helper = NULL;
2320 ModestMailOperationPrivate *priv;
2322 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2323 g_return_if_fail (TNY_IS_HEADER (header));
2325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2326 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2330 /* Check memory low */
2331 if (_check_memory_low (self)) {
2333 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2334 modest_mail_operation_notify_end (self);
2338 /* Get account and set it into mail_operation */
2339 folder = tny_header_get_folder (header);
2340 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2342 /* Check for cached messages */
2343 if (progress_feedback) {
2344 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2345 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2347 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2349 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2352 /* Create the helper */
2353 helper = g_slice_new0 (GetMsgInfo);
2354 helper->header = g_object_ref (header);
2355 helper->mail_op = g_object_ref (self);
2356 helper->user_callback = user_callback;
2357 helper->user_data = user_data;
2358 helper->destroy_notify = NULL;
2359 helper->last_total_bytes = 0;
2360 helper->sum_total_bytes = 0;
2361 helper->total_bytes = tny_header_get_message_size (header);
2362 helper->more_msgs = NULL;
2364 modest_mail_operation_notify_start (self);
2366 /* notify about the start of the operation */
2367 ModestMailOperationState *state;
2368 state = modest_mail_operation_clone_state (self);
2371 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2373 g_slice_free (ModestMailOperationState, state);
2375 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2377 g_object_unref (G_OBJECT (folder));
2381 get_msg_status_cb (GObject *obj,
2385 GetMsgInfo *helper = NULL;
2387 g_return_if_fail (status != NULL);
2389 /* Show only the status information we want */
2390 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2393 helper = (GetMsgInfo *) user_data;
2394 g_return_if_fail (helper != NULL);
2396 /* Notify progress */
2397 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2398 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2402 get_msg_async_cb (TnyFolder *folder,
2408 GetMsgInfo *info = NULL;
2409 ModestMailOperationPrivate *priv = NULL;
2412 info = (GetMsgInfo *) user_data;
2414 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2417 if (info->more_msgs) {
2418 tny_iterator_next (info->more_msgs);
2419 finished = (tny_iterator_is_done (info->more_msgs));
2421 finished = (priv->done == priv->total) ? TRUE : FALSE;
2424 /* If canceled by the user, ignore the error given by Tinymail */
2428 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2430 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2432 priv->error = g_error_copy ((const GError *) err);
2433 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2436 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2437 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2440 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2441 /* Set the success status before calling the user callback */
2442 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2446 /* Call the user callback */
2447 if (info->user_callback)
2448 info->user_callback (info->mail_op, info->header, canceled,
2449 msg, err, info->user_data);
2451 /* Notify about operation end if this is the last callback */
2453 /* Free user data */
2454 if (info->destroy_notify)
2455 info->destroy_notify (info->user_data);
2457 /* Notify about operation end */
2458 modest_mail_operation_notify_end (info->mail_op);
2461 if (info->more_msgs)
2462 g_object_unref (info->more_msgs);
2463 g_object_unref (info->header);
2464 g_object_unref (info->mail_op);
2465 g_slice_free (GetMsgInfo, info);
2466 } else if (info->more_msgs) {
2467 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2468 TnyFolder *folder = tny_header_get_folder (header);
2470 g_object_unref (info->header);
2471 info->header = g_object_ref (header);
2473 /* Retrieve the next message */
2474 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2476 g_object_unref (header);
2477 g_object_unref (folder);
2479 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2484 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2485 TnyList *header_list,
2486 GetMsgAsyncUserCallback user_callback,
2488 GDestroyNotify notify)
2490 ModestMailOperationPrivate *priv = NULL;
2492 TnyIterator *iter = NULL;
2493 gboolean has_uncached_messages;
2495 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2497 /* Init mail operation */
2498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2499 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2501 priv->total = tny_list_get_length(header_list);
2503 /* Check memory low */
2504 if (_check_memory_low (self)) {
2505 if (user_callback) {
2506 TnyHeader *header = NULL;
2509 if (tny_list_get_length (header_list) > 0) {
2510 iter = tny_list_create_iterator (header_list);
2511 header = (TnyHeader *) tny_iterator_get_current (iter);
2512 g_object_unref (iter);
2514 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2516 g_object_unref (header);
2520 /* Notify about operation end */
2521 modest_mail_operation_notify_end (self);
2525 /* Check uncached messages */
2526 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2527 !has_uncached_messages && !tny_iterator_is_done (iter);
2528 tny_iterator_next (iter)) {
2531 header = (TnyHeader *) tny_iterator_get_current (iter);
2532 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2533 has_uncached_messages = TRUE;
2534 g_object_unref (header);
2536 g_object_unref (iter);
2537 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2539 /* Get account and set it into mail_operation */
2540 if (tny_list_get_length (header_list) >= 1) {
2541 TnyIterator *iterator = tny_list_create_iterator (header_list);
2542 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2544 TnyFolder *folder = tny_header_get_folder (header);
2546 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2547 g_object_unref (folder);
2549 g_object_unref (header);
2551 g_object_unref (iterator);
2554 msg_list_size = compute_message_list_size (header_list, 0);
2556 modest_mail_operation_notify_start (self);
2557 iter = tny_list_create_iterator (header_list);
2558 if (!tny_iterator_is_done (iter)) {
2559 /* notify about the start of the operation */
2560 ModestMailOperationState *state;
2561 state = modest_mail_operation_clone_state (self);
2564 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2567 GetMsgInfo *msg_info = NULL;
2568 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2569 TnyFolder *folder = tny_header_get_folder (header);
2571 /* Create the message info */
2572 msg_info = g_slice_new0 (GetMsgInfo);
2573 msg_info->mail_op = g_object_ref (self);
2574 msg_info->header = g_object_ref (header);
2575 msg_info->more_msgs = g_object_ref (iter);
2576 msg_info->user_callback = user_callback;
2577 msg_info->user_data = user_data;
2578 msg_info->destroy_notify = notify;
2579 msg_info->last_total_bytes = 0;
2580 msg_info->sum_total_bytes = 0;
2581 msg_info->total_bytes = msg_list_size;
2583 /* The callback will call it per each header */
2584 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2586 /* Free and go on */
2587 g_object_unref (header);
2588 g_object_unref (folder);
2589 g_slice_free (ModestMailOperationState, state);
2591 g_object_unref (iter);
2596 remove_msgs_async_cb (TnyFolder *folder,
2601 gboolean expunge, leave_on_server;
2602 const gchar *account_name;
2604 TnyAccount *account;
2605 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2606 ModestMailOperation *self;
2607 ModestMailOperationPrivate *priv;
2609 self = (ModestMailOperation *) user_data;
2610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2612 if (canceled || err) {
2613 /* If canceled by the user, ignore the error given by Tinymail */
2615 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2617 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2618 priv->error = g_error_copy ((const GError *) err);
2619 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2622 modest_mail_operation_notify_end (self);
2623 g_object_unref (self);
2627 account = tny_folder_get_account (folder);
2628 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2630 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2632 proto = tny_account_get_proto (account);
2633 g_object_unref (account);
2636 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2638 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2639 modest_tny_folder_is_remote_folder (folder) == FALSE)
2645 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2650 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2652 gboolean remove_to_trash /*ignored*/)
2654 TnyFolder *folder = NULL;
2655 ModestMailOperationPrivate *priv;
2656 TnyIterator *iter = NULL;
2657 TnyHeader *header = NULL;
2658 TnyList *remove_headers = NULL;
2659 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2661 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2662 g_return_if_fail (TNY_IS_LIST (headers));
2664 if (remove_to_trash)
2665 g_warning ("remove to trash is not implemented");
2667 if (tny_list_get_length(headers) == 0) {
2668 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2669 goto cleanup; /* nothing to do */
2672 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2673 remove_headers = g_object_ref(headers);
2675 /* Get folder from first header and sync it */
2676 iter = tny_list_create_iterator (headers);
2677 header = TNY_HEADER (tny_iterator_get_current (iter));
2679 folder = tny_header_get_folder (header);
2680 if (!TNY_IS_FOLDER(folder)) {
2681 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2685 /* Don't remove messages that are being sent */
2686 if (modest_tny_folder_is_local_folder (folder)) {
2687 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2689 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2690 TnyTransportAccount *traccount = NULL;
2691 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2692 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2694 ModestTnySendQueueStatus status;
2695 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2697 if (TNY_IS_SEND_QUEUE (send_queue)) {
2698 TnyIterator *iter = tny_list_create_iterator(headers);
2699 g_object_unref(remove_headers);
2700 remove_headers = TNY_LIST(tny_simple_list_new());
2701 while (!tny_iterator_is_done(iter)) {
2703 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2704 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2705 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2706 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2707 tny_list_append(remove_headers, G_OBJECT(hdr));
2709 g_object_unref(hdr);
2711 tny_iterator_next(iter);
2713 g_object_unref(iter);
2715 g_object_unref(traccount);
2719 /* Get account and set it into mail_operation */
2720 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2721 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2722 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2724 /* remove message from folder */
2725 modest_mail_operation_notify_start (self);
2726 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2727 NULL, g_object_ref (self));
2731 g_object_unref (remove_headers);
2733 g_object_unref (header);
2735 g_object_unref (iter);
2737 g_object_unref (folder);
2741 notify_progress_of_multiple_messages (ModestMailOperation *self,
2743 gint *last_total_bytes,
2744 gint *sum_total_bytes,
2746 gboolean increment_done)
2748 ModestMailOperationPrivate *priv;
2749 ModestMailOperationState *state;
2750 gboolean is_num_bytes = FALSE;
2752 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2754 /* We know that tinymail sends us information about
2755 * transferred bytes with this particular message
2757 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2758 * I just added the 'if' so we don't get runtime warning)
2760 if (status->message)
2761 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2763 state = modest_mail_operation_clone_state (self);
2764 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2765 /* We know that we're in a different message when the
2766 total number of bytes to transfer is different. Of
2767 course it could fail if we're transferring messages
2768 of the same size, but this is a workarround */
2769 if (status->of_total != *last_total_bytes) {
2770 /* We need to increment the done when there is
2771 no information about each individual
2772 message, we need to do this in message
2773 transfers, and we don't do it for getting
2777 *sum_total_bytes += *last_total_bytes;
2778 *last_total_bytes = status->of_total;
2780 state->bytes_done += status->position + *sum_total_bytes;
2781 state->bytes_total = total_bytes;
2783 /* Notify the status change. Only notify about changes
2784 referred to bytes */
2785 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2789 g_slice_free (ModestMailOperationState, state);
2793 transfer_msgs_status_cb (GObject *obj,
2797 XFerMsgsAsyncHelper *helper;
2799 g_return_if_fail (status != NULL);
2801 /* Show only the status information we want */
2802 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2805 helper = (XFerMsgsAsyncHelper *) user_data;
2806 g_return_if_fail (helper != NULL);
2808 /* Notify progress */
2809 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2810 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2814 transfer_msgs_sync_folder_cb (TnyFolder *self,
2819 XFerMsgsAsyncHelper *helper;
2820 /* We don't care here about the results of the
2822 helper = (XFerMsgsAsyncHelper *) user_data;
2824 /* Notify about operation end */
2825 modest_mail_operation_notify_end (helper->mail_op);
2827 /* If user defined callback function was defined, call it */
2828 if (helper->user_callback)
2829 helper->user_callback (helper->mail_op, helper->user_data);
2832 if (helper->more_msgs)
2833 g_object_unref (helper->more_msgs);
2834 if (helper->headers)
2835 g_object_unref (helper->headers);
2836 if (helper->dest_folder)
2837 g_object_unref (helper->dest_folder);
2838 if (helper->mail_op)
2839 g_object_unref (helper->mail_op);
2840 g_slice_free (XFerMsgsAsyncHelper, helper);
2844 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2846 XFerMsgsAsyncHelper *helper;
2847 ModestMailOperation *self;
2848 ModestMailOperationPrivate *priv;
2849 gboolean finished = TRUE;
2851 helper = (XFerMsgsAsyncHelper *) user_data;
2852 self = helper->mail_op;
2854 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2857 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2859 priv->error = g_error_copy (err);
2861 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2862 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2863 if (helper->more_msgs) {
2864 /* We'll transfer the next message in the list */
2865 tny_iterator_next (helper->more_msgs);
2866 if (!tny_iterator_is_done (helper->more_msgs)) {
2867 GObject *next_header;
2868 g_object_unref (helper->headers);
2869 helper->headers = tny_simple_list_new ();
2870 next_header = tny_iterator_get_current (helper->more_msgs);
2871 tny_list_append (helper->headers, next_header);
2872 g_object_unref (next_header);
2878 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2883 /* Synchronize the source folder contents. This should
2884 be done by tinymail but the camel_folder_sync it's
2885 actually disabled in transfer_msgs_thread_clean
2886 because it's supposed to cause hangs */
2887 tny_folder_sync_async (folder, helper->delete,
2888 transfer_msgs_sync_folder_cb,
2891 /* Transfer more messages */
2892 tny_folder_transfer_msgs_async (folder,
2894 helper->dest_folder,
2897 transfer_msgs_status_cb,
2902 /* Computes the size of the messages the headers in the list belongs
2903 to. If num_elements is different from 0 then it only takes into
2904 account the first num_elements for the calculation */
2906 compute_message_list_size (TnyList *headers,
2910 guint size = 0, element = 0;
2912 /* If num_elements is not valid then take all into account */
2913 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2914 num_elements = tny_list_get_length (headers);
2916 iter = tny_list_create_iterator (headers);
2917 while (!tny_iterator_is_done (iter) && element < num_elements) {
2918 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2919 size += tny_header_get_message_size (header);
2920 g_object_unref (header);
2921 tny_iterator_next (iter);
2924 g_object_unref (iter);
2930 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2933 gboolean delete_original,
2934 XferMsgsAsyncUserCallback user_callback,
2937 ModestMailOperationPrivate *priv = NULL;
2938 TnyIterator *iter = NULL;
2939 TnyFolder *src_folder = NULL;
2940 XFerMsgsAsyncHelper *helper = NULL;
2941 TnyHeader *header = NULL;
2942 ModestTnyFolderRules rules = 0;
2943 TnyAccount *dst_account = NULL;
2944 gboolean leave_on_server;
2945 ModestMailOperationState *state;
2947 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2948 g_return_if_fail (headers && TNY_IS_LIST (headers));
2949 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2951 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2952 priv->total = tny_list_get_length (headers);
2954 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2955 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2957 /* Apply folder rules */
2958 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2959 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2960 /* Set status failed and set an error */
2961 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2962 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2963 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2964 _CS("ckct_ib_unable_to_paste_here"));
2965 /* Notify the queue */
2966 modest_mail_operation_notify_end (self);
2970 /* Get source folder */
2971 iter = tny_list_create_iterator (headers);
2972 header = TNY_HEADER (tny_iterator_get_current (iter));
2974 src_folder = tny_header_get_folder (header);
2975 g_object_unref (header);
2977 g_object_unref (iter);
2979 if (src_folder == NULL) {
2980 /* Notify the queue */
2981 modest_mail_operation_notify_end (self);
2983 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2988 /* Check folder source and destination */
2989 if (src_folder == folder) {
2990 /* Set status failed and set an error */
2991 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2992 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2993 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2994 _("mail_in_ui_folder_copy_target_error"));
2996 /* Notify the queue */
2997 modest_mail_operation_notify_end (self);
3000 g_object_unref (src_folder);
3004 /* Create the helper */
3005 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3006 helper->mail_op = g_object_ref(self);
3007 helper->dest_folder = g_object_ref(folder);
3008 helper->user_callback = user_callback;
3009 helper->user_data = user_data;
3010 helper->last_total_bytes = 0;
3011 helper->sum_total_bytes = 0;
3012 helper->total_bytes = compute_message_list_size (headers, 0);
3014 /* Get account and set it into mail_operation */
3015 priv->account = modest_tny_folder_get_account (src_folder);
3016 dst_account = modest_tny_folder_get_account (folder);
3018 if (priv->account == dst_account) {
3019 /* Transfer all messages at once using the fast
3020 * method. Note that depending on the server this
3021 * might not be that fast, and might not be
3022 * user-cancellable either */
3023 helper->headers = g_object_ref (headers);
3024 helper->more_msgs = NULL;
3026 /* Transfer messages one by one so the user can cancel
3029 helper->headers = tny_simple_list_new ();
3030 helper->more_msgs = tny_list_create_iterator (headers);
3031 hdr = tny_iterator_get_current (helper->more_msgs);
3032 tny_list_append (helper->headers, hdr);
3033 g_object_unref (hdr);
3036 /* If leave_on_server is set to TRUE then don't use
3037 delete_original, we always pass FALSE. This is because
3038 otherwise tinymail will try to sync the source folder and
3039 this could cause an error if we're offline while
3040 transferring an already downloaded message from a POP
3042 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3043 MODEST_PROTOCOL_STORE_POP) {
3044 const gchar *account_name;
3046 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3047 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3050 leave_on_server = FALSE;
3053 /* Do not delete messages if leave on server is TRUE */
3054 helper->delete = (leave_on_server) ? FALSE : delete_original;
3056 modest_mail_operation_notify_start (self);
3058 /* Start notifying progress */
3059 state = modest_mail_operation_clone_state (self);
3062 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3063 g_slice_free (ModestMailOperationState, state);
3065 tny_folder_transfer_msgs_async (src_folder,
3070 transfer_msgs_status_cb,
3072 g_object_unref (src_folder);
3073 g_object_unref (dst_account);
3078 on_refresh_folder (TnyFolder *folder,
3083 RefreshAsyncHelper *helper = NULL;
3084 ModestMailOperation *self = NULL;
3085 ModestMailOperationPrivate *priv = NULL;
3087 helper = (RefreshAsyncHelper *) user_data;
3088 self = helper->mail_op;
3089 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3091 g_return_if_fail(priv!=NULL);
3094 priv->error = g_error_copy (error);
3095 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3100 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3101 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3102 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3103 _("Error trying to refresh the contents of %s"),
3104 tny_folder_get_name (folder));
3108 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3111 /* Call user defined callback, if it exists */
3112 if (helper->user_callback) {
3114 /* This is not a GDK lock because we are a Tinymail callback and
3115 * Tinymail already acquires the Gdk lock */
3116 helper->user_callback (self, folder, helper->user_data);
3120 g_slice_free (RefreshAsyncHelper, helper);
3122 /* Notify about operation end */
3123 modest_mail_operation_notify_end (self);
3124 g_object_unref(self);
3128 on_refresh_folder_status_update (GObject *obj,
3132 RefreshAsyncHelper *helper = NULL;
3133 ModestMailOperation *self = NULL;
3134 ModestMailOperationPrivate *priv = NULL;
3135 ModestMailOperationState *state;
3137 g_return_if_fail (user_data != NULL);
3138 g_return_if_fail (status != NULL);
3140 /* Show only the status information we want */
3141 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3144 helper = (RefreshAsyncHelper *) user_data;
3145 self = helper->mail_op;
3146 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3148 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3150 priv->done = status->position;
3151 priv->total = status->of_total;
3153 state = modest_mail_operation_clone_state (self);
3155 /* This is not a GDK lock because we are a Tinymail callback and
3156 * Tinymail already acquires the Gdk lock */
3157 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3159 g_slice_free (ModestMailOperationState, state);
3163 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3165 RefreshAsyncUserCallback user_callback,
3168 ModestMailOperationPrivate *priv = NULL;
3169 RefreshAsyncHelper *helper = NULL;
3171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3173 /* Check memory low */
3174 if (_check_memory_low (self)) {
3176 user_callback (self, folder, user_data);
3177 /* Notify about operation end */
3178 modest_mail_operation_notify_end (self);
3182 /* Get account and set it into mail_operation */
3183 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3184 priv->account = modest_tny_folder_get_account (folder);
3185 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3187 /* Create the helper */
3188 helper = g_slice_new0 (RefreshAsyncHelper);
3189 helper->mail_op = g_object_ref(self);
3190 helper->user_callback = user_callback;
3191 helper->user_data = user_data;
3193 modest_mail_operation_notify_start (self);
3195 /* notify that the operation was started */
3196 ModestMailOperationState *state;
3197 state = modest_mail_operation_clone_state (self);
3200 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3202 g_slice_free (ModestMailOperationState, state);
3204 tny_folder_refresh_async (folder,
3206 on_refresh_folder_status_update,
3211 run_queue_stop (ModestTnySendQueue *queue,
3212 ModestMailOperation *self)
3214 ModestMailOperationPrivate *priv;
3216 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3217 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3218 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3220 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3222 modest_mail_operation_notify_end (self);
3223 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3224 g_object_unref (self);
3227 modest_mail_operation_run_queue (ModestMailOperation *self,
3228 ModestTnySendQueue *queue)
3230 ModestMailOperationPrivate *priv;
3232 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3233 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3236 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3237 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3238 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3240 modest_mail_operation_notify_start (self);
3241 g_object_ref (self);
3242 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3246 sync_folder_finish_callback (TnyFolder *self,
3252 ModestMailOperation *mail_op;
3253 ModestMailOperationPrivate *priv;
3255 mail_op = (ModestMailOperation *) user_data;
3256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3258 /* If canceled by the user, ignore the error given by Tinymail */
3260 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3262 /* If the operation was a sync then the status is
3263 failed, but if it's part of another operation then
3264 just set it as finished with errors */
3265 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3266 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3268 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3269 priv->error = g_error_copy ((const GError *) err);
3270 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3272 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3275 modest_mail_operation_notify_end (mail_op);
3276 g_object_unref (mail_op);
3280 modest_mail_operation_sync_folder (ModestMailOperation *self,
3281 TnyFolder *folder, gboolean expunge)
3283 ModestMailOperationPrivate *priv;
3285 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3286 g_return_if_fail (TNY_IS_FOLDER (folder));
3287 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3289 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3290 priv->account = modest_tny_folder_get_account (folder);
3291 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3293 modest_mail_operation_notify_start (self);
3294 g_object_ref (self);
3295 tny_folder_sync_async (folder, expunge,
3296 (TnyFolderCallback) sync_folder_finish_callback,
3301 modest_mail_operation_notify_start (ModestMailOperation *self)
3303 ModestMailOperationPrivate *priv = NULL;
3305 g_return_if_fail (self);
3307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3309 /* Ensure that all the fields are filled correctly */
3310 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3312 /* Notify the observers about the mail operation. We do not
3313 wrapp this emission because we assume that this function is
3314 always called from within the main lock */
3315 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3320 * It's used by the mail operation queue to notify the observers
3321 * attached to that signal that the operation finished. We need to use
3322 * that because tinymail does not give us the progress of a given
3323 * operation when it finishes (it directly calls the operation
3327 modest_mail_operation_notify_end (ModestMailOperation *self)
3329 ModestMailOperationPrivate *priv = NULL;
3331 g_return_if_fail (self);
3333 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3335 /* Notify the observers about the mail operation end. We do
3336 not wrapp this emission because we assume that this
3337 function is always called from within the main lock */
3338 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3340 /* Remove the error user data */
3341 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3342 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3346 modest_mail_operation_get_account (ModestMailOperation *self)
3348 ModestMailOperationPrivate *priv = NULL;
3350 g_return_val_if_fail (self, NULL);
3352 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3354 return (priv->account) ? g_object_ref (priv->account) : NULL;
3358 modest_mail_operation_noop (ModestMailOperation *self)
3360 ModestMailOperationPrivate *priv = NULL;
3362 g_return_if_fail (self);
3364 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3365 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3366 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3370 /* This mail operation does nothing actually */
3371 modest_mail_operation_notify_start (self);
3372 modest_mail_operation_notify_end (self);
3377 modest_mail_operation_to_string (ModestMailOperation *self)
3379 const gchar *type, *status, *account_id;
3380 ModestMailOperationPrivate *priv = NULL;
3382 g_return_val_if_fail (self, NULL);
3384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3386 /* new operations don't have anything interesting */
3387 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3388 return g_strdup_printf ("%p <new operation>", self);
3390 switch (priv->op_type) {
3391 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3392 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3393 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3394 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3395 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3396 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3397 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3398 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3399 default: type = "UNEXPECTED"; break;
3402 switch (priv->status) {
3403 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3404 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3405 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3406 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3407 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3408 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3409 default: status= "UNEXPECTED"; break;
3412 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3414 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3415 priv->done, priv->total,
3416 priv->error && priv->error->message ? priv->error->message : "");
3420 * Once the mail operations were objects this will be no longer
3421 * needed. I don't like it, but we need it for the moment
3424 _check_memory_low (ModestMailOperation *mail_op)
3426 if (modest_platform_check_memory_low (NULL, FALSE)) {
3427 ModestMailOperationPrivate *priv;
3429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3430 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3431 g_set_error (&(priv->error),
3432 MODEST_MAIL_OPERATION_ERROR,
3433 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3434 "Not enough memory to complete the operation");