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;
733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
734 if (info->html_body == NULL) {
735 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
736 info->bcc, info->subject, info->plain_body,
737 info->attachments_list, &attached,
740 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
741 info->bcc, info->subject, info->html_body,
742 info->plain_body, info->attachments_list,
743 info->images_list, &attached,
750 /* Set priority flags in message */
751 header = tny_msg_get_header (new_msg);
752 tny_header_set_flag (header, info->priority_flags);
754 /* Set attachment flags in message */
755 if (info->attachments_list != NULL && attached > 0)
756 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
758 g_object_unref (G_OBJECT(header));
760 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
762 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
763 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
764 "modest: failed to create a new msg\n");
772 g_free (info->plain_body);
773 g_free (info->html_body);
774 g_free (info->subject);
775 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
776 g_list_free (info->attachments_list);
777 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
778 g_list_free (info->images_list);
780 if (info->callback) {
781 CreateMsgIdleInfo *idle_info;
782 idle_info = g_slice_new0 (CreateMsgIdleInfo);
783 idle_info->mail_op = g_object_ref (info->mail_op);
784 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
785 idle_info->callback = info->callback;
786 idle_info->userdata = info->userdata;
787 g_idle_add (idle_create_msg_cb, idle_info);
789 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
792 g_object_unref (info->mail_op);
793 g_slice_free (CreateMsgInfo, info);
794 if (new_msg) g_object_unref(new_msg);
800 modest_mail_operation_create_msg (ModestMailOperation *self,
801 const gchar *from, const gchar *to,
802 const gchar *cc, const gchar *bcc,
803 const gchar *subject, const gchar *plain_body,
804 const gchar *html_body,
805 const GList *attachments_list,
806 const GList *images_list,
807 TnyHeaderFlags priority_flags,
808 ModestMailOperationCreateMsgCallback callback,
811 CreateMsgInfo *info = NULL;
813 info = g_slice_new0 (CreateMsgInfo);
814 info->mail_op = g_object_ref (self);
816 info->from = g_strdup (from);
817 info->to = g_strdup (to);
818 info->cc = g_strdup (cc);
819 info->bcc = g_strdup (bcc);
820 info->subject = g_strdup (subject);
821 info->plain_body = g_strdup (plain_body);
822 info->html_body = g_strdup (html_body);
823 info->attachments_list = g_list_copy ((GList *) attachments_list);
824 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
825 info->images_list = g_list_copy ((GList *) images_list);
826 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
827 info->priority_flags = priority_flags;
829 info->callback = callback;
830 info->userdata = userdata;
832 g_thread_create (create_msg_thread, info, FALSE, NULL);
837 TnyTransportAccount *transport_account;
842 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
846 ModestMailOperationPrivate *priv = NULL;
847 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
848 TnyFolder *draft_folder = NULL;
849 TnyFolder *outbox_folder = NULL;
850 TnyHeader *header = NULL;
852 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
855 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
856 modest_mail_operation_notify_end (self);
860 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
861 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
862 modest_mail_operation_notify_end (self);
866 /* Call mail operation */
867 modest_mail_operation_send_mail (self, info->transport_account, msg);
869 if (info->draft_msg != NULL) {
870 TnyList *tmp_headers = NULL;
871 TnyFolder *folder = NULL;
872 TnyFolder *src_folder = NULL;
873 TnyFolderType folder_type;
874 TnyTransportAccount *transport_account = NULL;
876 /* To remove the old mail from its source folder, we need to get the
877 * transport account of the original draft message (the transport account
878 * might have been changed by the user) */
879 header = tny_msg_get_header (info->draft_msg);
880 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
881 modest_runtime_get_account_store(), header);
882 if (transport_account == NULL)
883 transport_account = g_object_ref(info->transport_account);
884 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
885 TNY_FOLDER_TYPE_DRAFTS);
886 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
887 TNY_FOLDER_TYPE_OUTBOX);
888 g_object_unref(transport_account);
891 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
895 if (!outbox_folder) {
896 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
901 folder = tny_msg_get_folder (info->draft_msg);
902 if (folder == NULL) goto end;
903 folder_type = modest_tny_folder_guess_folder_type (folder);
905 if (folder_type == TNY_FOLDER_TYPE_INVALID)
906 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
908 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
909 src_folder = outbox_folder;
911 src_folder = draft_folder;
913 /* Note: This can fail (with a warning) if the message is not really already in a folder,
914 * because this function requires it to have a UID. */
915 tmp_headers = tny_simple_list_new ();
916 tny_list_append (tmp_headers, (GObject*) header);
917 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
918 g_object_unref (tmp_headers);
919 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
921 g_object_unref (folder);
926 g_object_unref (header);
928 g_object_unref (info->draft_msg);
930 g_object_unref (draft_folder);
932 g_object_unref (outbox_folder);
933 if (info->transport_account)
934 g_object_unref (info->transport_account);
935 g_slice_free (SendNewMailInfo, info);
939 modest_mail_operation_send_new_mail (ModestMailOperation *self,
940 TnyTransportAccount *transport_account,
942 const gchar *from, const gchar *to,
943 const gchar *cc, const gchar *bcc,
944 const gchar *subject, const gchar *plain_body,
945 const gchar *html_body,
946 const GList *attachments_list,
947 const GList *images_list,
948 TnyHeaderFlags priority_flags)
950 ModestMailOperationPrivate *priv = NULL;
951 SendNewMailInfo *info;
953 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
954 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
956 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
957 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
958 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
959 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
961 /* Check parametters */
963 /* Set status failed and set an error */
964 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
965 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
966 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
967 _("Error trying to send a mail. You need to set at least one recipient"));
970 info = g_slice_new0 (SendNewMailInfo);
971 info->transport_account = transport_account;
972 if (transport_account)
973 g_object_ref (transport_account);
974 info->draft_msg = draft_msg;
976 g_object_ref (draft_msg);
979 modest_mail_operation_notify_start (self);
980 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
981 attachments_list, images_list, priority_flags,
982 modest_mail_operation_send_new_mail_cb, info);
988 TnyTransportAccount *transport_account;
990 SaveToDraftstCallback callback;
994 ModestMailOperation *mailop;
995 } SaveToDraftsAddMsgInfo;
998 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1003 ModestMailOperationPrivate *priv = NULL;
1004 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1005 GError *io_error = NULL;
1007 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1009 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1010 io_error = priv->error;
1014 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1015 g_error_free(priv->error);
1018 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1020 if ((!priv->error) && (info->draft_msg != NULL)) {
1021 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1022 TnyFolder *src_folder = tny_header_get_folder (header);
1024 /* Remove the old draft */
1025 tny_folder_remove_msg (src_folder, header, NULL);
1027 /* Synchronize to expunge and to update the msg counts */
1028 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1029 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1031 g_object_unref (G_OBJECT(header));
1032 g_object_unref (G_OBJECT(src_folder));
1036 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1038 g_error_free (io_error);
1041 } else if (io_error) {
1042 priv->error = io_error;
1043 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1045 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1048 /* Call the user callback */
1050 info->callback (info->mailop, info->msg, info->user_data);
1052 if (info->transport_account)
1053 g_object_unref (G_OBJECT(info->transport_account));
1054 if (info->draft_msg)
1055 g_object_unref (G_OBJECT (info->draft_msg));
1057 g_object_unref (G_OBJECT(info->drafts));
1059 g_object_unref (G_OBJECT (info->msg));
1061 modest_mail_operation_notify_end (info->mailop);
1062 g_object_unref(info->mailop);
1063 g_slice_free (SaveToDraftsAddMsgInfo, info);
1068 TnyTransportAccount *transport_account;
1070 SaveToDraftstCallback callback;
1075 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1079 TnyFolder *drafts = NULL;
1080 ModestMailOperationPrivate *priv = NULL;
1081 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1083 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1086 if (!(priv->error)) {
1087 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1088 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1089 "modest: failed to create a new msg\n");
1092 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1093 TNY_FOLDER_TYPE_DRAFTS);
1094 if (!drafts && !(priv->error)) {
1095 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1096 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1097 "modest: failed to create a new msg\n");
1101 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1102 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1103 cb_info->transport_account = g_object_ref(info->transport_account);
1104 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1105 cb_info->callback = info->callback;
1106 cb_info->user_data = info->user_data;
1107 cb_info->drafts = g_object_ref(drafts);
1108 cb_info->msg = g_object_ref(msg);
1109 cb_info->mailop = g_object_ref(self);
1110 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1113 /* Call the user callback */
1114 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1116 info->callback (self, msg, info->user_data);
1117 modest_mail_operation_notify_end (self);
1121 g_object_unref (G_OBJECT(drafts));
1122 if (info->draft_msg)
1123 g_object_unref (G_OBJECT (info->draft_msg));
1124 if (info->transport_account)
1125 g_object_unref (G_OBJECT(info->transport_account));
1126 g_slice_free (SaveToDraftsInfo, info);
1130 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1131 TnyTransportAccount *transport_account,
1133 const gchar *from, const gchar *to,
1134 const gchar *cc, const gchar *bcc,
1135 const gchar *subject, const gchar *plain_body,
1136 const gchar *html_body,
1137 const GList *attachments_list,
1138 const GList *images_list,
1139 TnyHeaderFlags priority_flags,
1140 SaveToDraftstCallback callback,
1143 ModestMailOperationPrivate *priv = NULL;
1144 SaveToDraftsInfo *info = NULL;
1146 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1147 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1149 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1151 /* Get account and set it into mail_operation */
1152 priv->account = g_object_ref (transport_account);
1153 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1155 info = g_slice_new0 (SaveToDraftsInfo);
1156 info->transport_account = g_object_ref (transport_account);
1157 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1158 info->callback = callback;
1159 info->user_data = user_data;
1161 modest_mail_operation_notify_start (self);
1162 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1163 attachments_list, images_list, priority_flags,
1164 modest_mail_operation_save_to_drafts_cb, info);
1169 ModestMailOperation *mail_op;
1170 TnyMimePart *mime_part;
1172 GetMimePartSizeCallback callback;
1174 } GetMimePartSizeInfo;
1176 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1177 /* We use this folder observer to track the headers that have been
1178 * added to a folder */
1181 TnyList *new_headers;
1182 } InternalFolderObserver;
1185 GObjectClass parent;
1186 } InternalFolderObserverClass;
1188 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1190 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1191 internal_folder_observer,
1193 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1197 foreach_add_item (gpointer header, gpointer user_data)
1199 tny_list_prepend (TNY_LIST (user_data),
1203 /* This is the method that looks for new messages in a folder */
1205 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1207 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1209 TnyFolderChangeChanged changed;
1211 changed = tny_folder_change_get_changed (change);
1213 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1216 /* Get added headers */
1217 list = tny_simple_list_new ();
1218 tny_folder_change_get_added_headers (change, list);
1220 /* Add them to the folder observer */
1221 tny_list_foreach (list, foreach_add_item,
1222 derived->new_headers);
1224 g_object_unref (G_OBJECT (list));
1229 internal_folder_observer_init (InternalFolderObserver *self)
1231 self->new_headers = tny_simple_list_new ();
1234 internal_folder_observer_finalize (GObject *object)
1236 InternalFolderObserver *self;
1238 self = (InternalFolderObserver *) object;
1239 g_object_unref (self->new_headers);
1241 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1244 tny_folder_observer_init (TnyFolderObserverIface *iface)
1246 iface->update = internal_folder_observer_update;
1249 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1251 GObjectClass *object_class;
1253 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1254 object_class = (GObjectClass*) klass;
1255 object_class->finalize = internal_folder_observer_finalize;
1259 destroy_update_account_info (UpdateAccountInfo *info)
1261 g_free (info->account_name);
1262 g_object_unref (info->folders);
1263 g_object_unref (info->mail_op);
1264 g_slice_free (UpdateAccountInfo, info);
1269 update_account_send_mail (UpdateAccountInfo *info)
1271 TnyTransportAccount *transport_account = NULL;
1273 /* Get the transport account */
1274 transport_account = (TnyTransportAccount *)
1275 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1276 info->account_name);
1278 if (transport_account) {
1279 ModestTnySendQueue *send_queue;
1283 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1284 g_object_unref (transport_account);
1286 if (TNY_IS_SEND_QUEUE (send_queue)) {
1287 /* Get outbox folder */
1288 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1289 if (outbox) { /* this could fail in some cases */
1290 num_messages = tny_folder_get_all_count (outbox);
1291 g_object_unref (outbox);
1293 g_warning ("%s: could not get outbox", __FUNCTION__);
1297 if (num_messages != 0) {
1298 /* Reenable suspended items */
1299 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1302 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1303 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1311 update_account_get_msg_async_cb (TnyFolder *folder,
1317 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1318 ModestMailOperationPrivate *priv;
1320 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1323 if (TNY_IS_MSG (msg)) {
1324 TnyHeader *header = tny_msg_get_header (msg);
1327 ModestMailOperationState *state;
1328 state = modest_mail_operation_clone_state (msg_info->mail_op);
1329 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1330 state->bytes_done = msg_info->sum_total_bytes;
1331 state->bytes_total = msg_info->total_bytes;
1333 /* Notify the status change. Only notify about changes
1334 referred to bytes */
1335 g_signal_emit (G_OBJECT (msg_info->mail_op),
1336 signals[PROGRESS_CHANGED_SIGNAL],
1339 g_object_unref (header);
1340 g_slice_free (ModestMailOperationState, state);
1344 if (priv->done == priv->total) {
1345 TnyList *new_headers;
1346 UpdateAccountInfo *info;
1348 /* After getting all the messages send the ones in the
1350 info = (UpdateAccountInfo *) msg_info->user_data;
1351 update_account_send_mail (info);
1353 /* Check if the operation was a success */
1355 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1357 /* Call the user callback and free */
1358 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1359 update_account_notify_user_and_free (info, new_headers);
1360 g_object_unref (new_headers);
1362 /* Delete the helper */
1363 g_object_unref (msg_info->more_msgs);
1364 g_object_unref (msg_info->mail_op);
1365 g_slice_free (GetMsgInfo, msg_info);
1370 update_account_notify_user_and_free (UpdateAccountInfo *info,
1371 TnyList *new_headers)
1373 /* Set the account back to not busy */
1374 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1375 info->account_name, FALSE);
1379 info->callback (info->mail_op, new_headers, info->user_data);
1381 /* Mail operation end */
1382 modest_mail_operation_notify_end (info->mail_op);
1386 g_object_unref (new_headers);
1387 destroy_update_account_info (info);
1391 inbox_refreshed_cb (TnyFolder *inbox,
1396 UpdateAccountInfo *info;
1397 ModestMailOperationPrivate *priv;
1398 TnyIterator *new_headers_iter;
1399 GPtrArray *new_headers_array = NULL;
1400 gint max_size, retrieve_limit, i;
1401 ModestAccountMgr *mgr;
1402 ModestAccountRetrieveType retrieve_type;
1403 TnyList *new_headers = NULL;
1404 gboolean headers_only, ignore_limit;
1406 info = (UpdateAccountInfo *) user_data;
1407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1408 mgr = modest_runtime_get_account_mgr ();
1410 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1411 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1413 if (canceled || err) {
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1416 priv->error = g_error_copy (err);
1418 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1419 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1422 tny_folder_remove_observer (inbox, info->inbox_observer);
1423 g_object_unref (info->inbox_observer);
1424 info->inbox_observer = NULL;
1426 /* Notify the user about the error and then exit */
1427 update_account_notify_user_and_free (info, NULL);
1432 /* Try to send anyway */
1436 /* Get the message max size */
1437 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1438 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1440 max_size = G_MAXINT;
1442 max_size = max_size * KB;
1444 /* Create the new headers array. We need it to sort the
1445 new headers by date */
1446 new_headers_array = g_ptr_array_new ();
1447 if (info->inbox_observer) {
1448 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1449 while (!tny_iterator_is_done (new_headers_iter)) {
1450 TnyHeader *header = NULL;
1452 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1453 /* Apply per-message size limits */
1454 if (tny_header_get_message_size (header) < max_size)
1455 g_ptr_array_add (new_headers_array, g_object_ref (header));
1457 g_object_unref (header);
1458 tny_iterator_next (new_headers_iter);
1460 g_object_unref (new_headers_iter);
1462 tny_folder_remove_observer (inbox, info->inbox_observer);
1463 g_object_unref (info->inbox_observer);
1464 info->inbox_observer = NULL;
1467 if (new_headers_array->len == 0) {
1468 g_ptr_array_free (new_headers_array, FALSE);
1472 /* Get per-account message amount retrieval limit */
1473 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1474 if (retrieve_limit == 0)
1475 retrieve_limit = G_MAXINT;
1477 /* Get per-account retrieval type */
1478 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1479 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1482 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1484 /* Ask the users if they want to retrieve all the messages
1485 even though the limit was exceeded */
1486 ignore_limit = FALSE;
1487 if (new_headers_array->len > retrieve_limit) {
1488 /* Ask the user if a callback has been specified and
1489 if the mail operation has a source (this means that
1490 was invoked by the user and not automatically by a
1492 if (info->retrieve_all_cb && priv->source)
1493 ignore_limit = info->retrieve_all_cb (priv->source,
1494 new_headers_array->len,
1498 /* Copy the headers to a list and free the array */
1499 new_headers = tny_simple_list_new ();
1500 for (i=0; i < new_headers_array->len; i++) {
1501 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1502 tny_list_append (new_headers, G_OBJECT (header));
1504 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1505 g_ptr_array_free (new_headers_array, FALSE);
1507 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1510 GetMsgInfo *msg_info;
1514 priv->total = tny_list_get_length (new_headers);
1516 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1518 iter = tny_list_create_iterator (new_headers);
1520 /* Create the message info */
1521 msg_info = g_slice_new0 (GetMsgInfo);
1522 msg_info->mail_op = g_object_ref (info->mail_op);
1523 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1524 msg_info->more_msgs = g_object_ref (iter);
1525 msg_info->user_data = info;
1527 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1528 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1529 TnyFolder *folder = tny_header_get_folder (header);
1531 /* Get message in an async way */
1532 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1535 g_object_unref (folder);
1538 tny_iterator_next (iter);
1540 g_object_unref (iter);
1542 /* The mail operation will finish when the last
1543 message is retrieved */
1547 /* If we don't have to retrieve the new messages then
1549 update_account_send_mail (info);
1551 /* Check if the operation was a success */
1553 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1555 /* Call the user callback and free */
1556 update_account_notify_user_and_free (info, new_headers);
1560 inbox_refresh_status_update (GObject *obj,
1564 UpdateAccountInfo *info = NULL;
1565 ModestMailOperation *self = NULL;
1566 ModestMailOperationPrivate *priv = NULL;
1567 ModestMailOperationState *state;
1569 g_return_if_fail (user_data != NULL);
1570 g_return_if_fail (status != NULL);
1572 /* Show only the status information we want */
1573 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1576 info = (UpdateAccountInfo *) user_data;
1577 self = info->mail_op;
1578 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1582 priv->done = status->position;
1583 priv->total = status->of_total;
1585 state = modest_mail_operation_clone_state (self);
1587 /* This is not a GDK lock because we are a Tinymail callback and
1588 * Tinymail already acquires the Gdk lock */
1589 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1591 g_slice_free (ModestMailOperationState, state);
1595 recurse_folders_async_cb (TnyFolderStore *folder_store,
1601 UpdateAccountInfo *info;
1602 ModestMailOperationPrivate *priv;
1604 info = (UpdateAccountInfo *) user_data;
1605 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1607 if (err || canceled) {
1608 /* If the error was previosly set by another callback
1609 don't set it again */
1611 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1613 priv->error = g_error_copy (err);
1615 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1616 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1620 /* We're not getting INBOX children if we don't want to poke all */
1621 TnyIterator *iter = tny_list_create_iterator (list);
1622 while (!tny_iterator_is_done (iter)) {
1623 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1625 /* Add to the list of all folders */
1626 tny_list_append (info->folders, (GObject *) folder);
1628 if (info->poke_all) {
1629 TnyList *folders = tny_simple_list_new ();
1630 /* Add pending call */
1631 info->pending_calls++;
1633 tny_folder_store_get_folders_async (folder, folders, NULL,
1634 recurse_folders_async_cb,
1636 g_object_unref (folders);
1639 g_object_unref (G_OBJECT (folder));
1641 tny_iterator_next (iter);
1643 g_object_unref (G_OBJECT (iter));
1646 /* Remove my own pending call */
1647 info->pending_calls--;
1649 /* This means that we have all the folders */
1650 if (info->pending_calls == 0) {
1651 TnyIterator *iter_all_folders;
1652 TnyFolder *inbox = NULL;
1654 /* If there was any error do not continue */
1656 update_account_notify_user_and_free (info, NULL);
1660 iter_all_folders = tny_list_create_iterator (info->folders);
1662 /* Do a poke status over all folders */
1663 while (!tny_iterator_is_done (iter_all_folders) &&
1664 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1665 TnyFolder *folder = NULL;
1667 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1669 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1670 /* Get a reference to the INBOX */
1671 inbox = g_object_ref (folder);
1673 /* Issue a poke status over the folder */
1675 tny_folder_poke_status (folder);
1678 /* Free and go to next */
1679 g_object_unref (folder);
1680 tny_iterator_next (iter_all_folders);
1682 g_object_unref (iter_all_folders);
1684 /* Refresh the INBOX */
1686 /* Refresh the folder. Our observer receives
1687 * the new emails during folder refreshes, so
1688 * we can use observer->new_headers
1690 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1691 tny_folder_add_observer (inbox, info->inbox_observer);
1693 /* Refresh the INBOX */
1694 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1695 g_object_unref (inbox);
1697 /* We could not perform the inbox refresh but
1698 we'll try to send mails anyway */
1699 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1705 modest_mail_operation_update_account (ModestMailOperation *self,
1706 const gchar *account_name,
1708 gboolean interactive,
1709 RetrieveAllCallback retrieve_all_cb,
1710 UpdateAccountCallback callback,
1713 UpdateAccountInfo *info = NULL;
1714 ModestMailOperationPrivate *priv = NULL;
1715 ModestTnyAccountStore *account_store = NULL;
1717 ModestMailOperationState *state;
1719 /* Init mail operation */
1720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1723 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1724 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1726 /* Get the store account */
1727 account_store = modest_runtime_get_account_store ();
1729 modest_tny_account_store_get_server_account (account_store,
1731 TNY_ACCOUNT_TYPE_STORE);
1733 /* The above function could return NULL */
1734 if (!priv->account) {
1735 /* Check if the operation was a success */
1736 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1737 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1739 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1741 /* Call the user callback */
1743 callback (self, NULL, user_data);
1745 /* Notify about operation end */
1746 modest_mail_operation_notify_end (self);
1751 /* We have once seen priv->account getting finalized during this code,
1752 * therefore adding a reference (bug #82296) */
1754 g_object_ref (priv->account);
1756 /* Create the helper object */
1757 info = g_slice_new0 (UpdateAccountInfo);
1758 info->pending_calls = 1;
1759 info->folders = tny_simple_list_new ();
1760 info->mail_op = g_object_ref (self);
1761 info->poke_all = poke_all;
1762 info->interactive = interactive;
1763 info->account_name = g_strdup (account_name);
1764 info->callback = callback;
1765 info->user_data = user_data;
1766 info->retrieve_all_cb = retrieve_all_cb;
1768 /* Set account busy */
1769 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1770 modest_mail_operation_notify_start (self);
1772 /* notify about the start of the operation */
1773 state = modest_mail_operation_clone_state (self);
1777 /* Start notifying progress */
1778 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1779 g_slice_free (ModestMailOperationState, state);
1781 /* Get all folders and continue in the callback */
1782 folders = tny_simple_list_new ();
1783 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1785 recurse_folders_async_cb,
1787 g_object_unref (folders);
1789 g_object_unref (priv->account);
1794 * Used to notify the queue from the main
1795 * loop. We call it inside an idle call to achieve that
1798 idle_notify_queue (gpointer data)
1800 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1802 gdk_threads_enter ();
1803 modest_mail_operation_notify_end (mail_op);
1804 gdk_threads_leave ();
1805 g_object_unref (mail_op);
1811 compare_headers_by_date (gconstpointer a,
1814 TnyHeader **header1, **header2;
1815 time_t sent1, sent2;
1817 header1 = (TnyHeader **) a;
1818 header2 = (TnyHeader **) b;
1820 sent1 = tny_header_get_date_sent (*header1);
1821 sent2 = tny_header_get_date_sent (*header2);
1823 /* We want the most recent ones (greater time_t) at the
1832 /* ******************************************************************* */
1833 /* ************************** STORE ACTIONS ************************* */
1834 /* ******************************************************************* */
1837 ModestMailOperation *mail_op;
1838 CreateFolderUserCallback callback;
1844 create_folder_cb (TnyFolderStore *parent_folder,
1846 TnyFolder *new_folder,
1850 ModestMailOperationPrivate *priv;
1851 CreateFolderInfo *info;
1853 info = (CreateFolderInfo *) user_data;
1854 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1856 if (canceled || err) {
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1859 priv->error = g_error_copy (err);
1861 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1862 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1865 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1868 /* The user will unref the new_folder */
1870 info->callback (info->mail_op, parent_folder,
1871 new_folder, info->user_data);
1873 /* Notify about operation end */
1874 modest_mail_operation_notify_end (info->mail_op);
1877 g_object_unref (info->mail_op);
1878 g_slice_free (CreateFolderInfo, info);
1882 modest_mail_operation_create_folder (ModestMailOperation *self,
1883 TnyFolderStore *parent,
1885 CreateFolderUserCallback callback,
1888 ModestMailOperationPrivate *priv;
1890 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1891 g_return_if_fail (name);
1893 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1894 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1895 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1896 g_object_ref (parent) :
1897 modest_tny_folder_get_account (TNY_FOLDER (parent));
1899 /* Check for already existing folder */
1900 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1901 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1902 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1903 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1904 _CS("ckdg_ib_folder_already_exists"));
1908 if (TNY_IS_FOLDER (parent)) {
1909 /* Check folder rules */
1910 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1911 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1912 /* Set status failed and set an error */
1913 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1914 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1915 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1916 _("mail_in_ui_folder_create_error"));
1920 if (!strcmp (name, " ") || strchr (name, '/')) {
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1924 _("mail_in_ui_folder_create_error"));
1928 CreateFolderInfo *info;
1930 info = g_slice_new0 (CreateFolderInfo);
1931 info->mail_op = g_object_ref (self);
1932 info->callback = callback;
1933 info->user_data = user_data;
1935 modest_mail_operation_notify_start (self);
1937 /* Create the folder */
1938 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1941 /* Call the user callback anyway */
1943 callback (self, parent, NULL, user_data);
1944 /* Notify about operation end */
1945 modest_mail_operation_notify_end (self);
1950 modest_mail_operation_remove_folder (ModestMailOperation *self,
1952 gboolean remove_to_trash)
1954 ModestMailOperationPrivate *priv;
1955 ModestTnyFolderRules rules;
1957 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1958 g_return_if_fail (TNY_IS_FOLDER (folder));
1960 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1962 /* Check folder rules */
1963 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1964 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1965 /* Set status failed and set an error */
1966 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1967 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1968 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1969 _("mail_in_ui_folder_delete_error"));
1973 /* Get the account */
1974 priv->account = modest_tny_folder_get_account (folder);
1975 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1977 /* Delete folder or move to trash */
1978 if (remove_to_trash) {
1979 TnyFolder *trash_folder = NULL;
1980 trash_folder = modest_tny_account_get_special_folder (priv->account,
1981 TNY_FOLDER_TYPE_TRASH);
1982 /* TODO: error_handling */
1984 modest_mail_operation_notify_start (self);
1985 modest_mail_operation_xfer_folder (self, folder,
1986 TNY_FOLDER_STORE (trash_folder),
1988 g_object_unref (trash_folder);
1990 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1993 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1995 modest_mail_operation_notify_start (self);
1996 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1997 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2000 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2002 g_object_unref (parent);
2004 g_warning ("%s: could not get parent folder", __FUNCTION__);
2008 /* Notify about operation end */
2009 modest_mail_operation_notify_end (self);
2013 transfer_folder_status_cb (GObject *obj,
2017 ModestMailOperation *self;
2018 ModestMailOperationPrivate *priv;
2019 ModestMailOperationState *state;
2020 XFerFolderAsyncHelper *helper;
2022 g_return_if_fail (status != NULL);
2024 /* Show only the status information we want */
2025 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2028 helper = (XFerFolderAsyncHelper *) user_data;
2029 g_return_if_fail (helper != NULL);
2031 self = helper->mail_op;
2032 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2034 priv->done = status->position;
2035 priv->total = status->of_total;
2037 state = modest_mail_operation_clone_state (self);
2039 /* This is not a GDK lock because we are a Tinymail callback
2040 * which is already GDK locked by Tinymail */
2042 /* no gdk_threads_enter (), CHECKED */
2044 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2046 /* no gdk_threads_leave (), CHECKED */
2048 g_slice_free (ModestMailOperationState, state);
2053 transfer_folder_cb (TnyFolder *folder,
2055 TnyFolderStore *into,
2056 TnyFolder *new_folder,
2060 XFerFolderAsyncHelper *helper;
2061 ModestMailOperation *self = NULL;
2062 ModestMailOperationPrivate *priv = NULL;
2064 helper = (XFerFolderAsyncHelper *) user_data;
2065 g_return_if_fail (helper != NULL);
2067 self = helper->mail_op;
2068 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2071 priv->error = g_error_copy (err);
2073 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2074 } else if (cancelled) {
2075 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2076 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2077 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2078 _("Transference of %s was cancelled."),
2079 tny_folder_get_name (folder));
2082 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2085 /* Notify about operation end */
2086 modest_mail_operation_notify_end (self);
2088 /* If user defined callback function was defined, call it */
2089 if (helper->user_callback) {
2091 /* This is not a GDK lock because we are a Tinymail callback
2092 * which is already GDK locked by Tinymail */
2094 /* no gdk_threads_enter (), CHECKED */
2095 helper->user_callback (self, new_folder, helper->user_data);
2096 /* no gdk_threads_leave () , CHECKED */
2100 g_object_unref (helper->mail_op);
2101 g_slice_free (XFerFolderAsyncHelper, helper);
2106 * This function checks if the new name is a valid name for our local
2107 * folders account. The new name could not be the same than then name
2108 * of any of the mandatory local folders
2110 * We can not rely on tinymail because tinymail does not check the
2111 * name of the virtual folders that the account could have in the case
2112 * that we're doing a rename (because it directly calls Camel which
2113 * knows nothing about our virtual folders).
2115 * In the case of an actual copy/move (i.e. move/copy a folder between
2116 * accounts) tinymail uses the tny_folder_store_create_account which
2117 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2118 * checks the new name of the folder, so this call in that case
2119 * wouldn't be needed. *But* NOTE that if tinymail changes its
2120 * implementation (if folder transfers within the same account is no
2121 * longer implemented as a rename) this call will allow Modest to work
2124 * If the new name is not valid, this function will set the status to
2125 * failed and will set also an error in the mail operation
2128 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2129 TnyFolderStore *into,
2130 const gchar *new_name)
2132 if (TNY_IS_ACCOUNT (into) &&
2133 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2134 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2136 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2137 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2138 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2139 _CS("ckdg_ib_folder_already_exists"));
2146 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2148 TnyFolderStore *parent,
2149 gboolean delete_original,
2150 XferFolderAsyncUserCallback user_callback,
2153 ModestMailOperationPrivate *priv = NULL;
2154 ModestTnyFolderRules parent_rules = 0, rules;
2155 XFerFolderAsyncHelper *helper = NULL;
2156 const gchar *folder_name = NULL;
2157 const gchar *error_msg;
2159 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2160 g_return_if_fail (TNY_IS_FOLDER (folder));
2161 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2164 folder_name = tny_folder_get_name (folder);
2166 /* Set the error msg */
2167 error_msg = _("mail_in_ui_folder_move_target_error");
2169 /* Get account and set it into mail_operation */
2170 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2171 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2172 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2174 /* Get folder rules */
2175 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2176 if (TNY_IS_FOLDER (parent))
2177 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2179 /* Apply operation constraints */
2180 if ((gpointer) parent == (gpointer) folder ||
2181 (!TNY_IS_FOLDER_STORE (parent)) ||
2182 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2185 } else if (TNY_IS_FOLDER (parent) &&
2186 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2190 } else if (TNY_IS_FOLDER (parent) &&
2191 TNY_IS_FOLDER_STORE (folder) &&
2192 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2193 TNY_FOLDER_STORE (folder))) {
2194 /* Do not move a parent into a child */
2196 } else if (TNY_IS_FOLDER_STORE (parent) &&
2197 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2198 /* Check that the new folder name is not used by any
2201 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2202 /* Check that the new folder name is not used by any
2203 special local folder */
2206 /* Create the helper */
2207 helper = g_slice_new0 (XFerFolderAsyncHelper);
2208 helper->mail_op = g_object_ref (self);
2209 helper->user_callback = user_callback;
2210 helper->user_data = user_data;
2212 /* Move/Copy folder */
2213 modest_mail_operation_notify_start (self);
2214 tny_folder_copy_async (folder,
2216 tny_folder_get_name (folder),
2219 transfer_folder_status_cb,
2225 /* Set status failed and set an error */
2226 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2227 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2228 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2231 /* Call the user callback if exists */
2233 user_callback (self, NULL, user_data);
2235 /* Notify the queue */
2236 modest_mail_operation_notify_end (self);
2240 modest_mail_operation_rename_folder (ModestMailOperation *self,
2243 XferFolderAsyncUserCallback user_callback,
2246 ModestMailOperationPrivate *priv;
2247 ModestTnyFolderRules rules;
2248 XFerFolderAsyncHelper *helper;
2250 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2251 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2252 g_return_if_fail (name);
2254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2256 /* Get account and set it into mail_operation */
2257 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2258 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2260 /* Check folder rules */
2261 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2262 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2264 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2267 TnyFolderStore *into;
2269 into = tny_folder_get_folder_store (folder);
2271 /* Check that the new folder name is not used by any
2272 special local folder */
2273 if (new_name_valid_if_local_account (priv, into, name)) {
2274 /* Create the helper */
2275 helper = g_slice_new0 (XFerFolderAsyncHelper);
2276 helper->mail_op = g_object_ref(self);
2277 helper->user_callback = user_callback;
2278 helper->user_data = user_data;
2280 /* Rename. Camel handles folder subscription/unsubscription */
2281 modest_mail_operation_notify_start (self);
2282 tny_folder_copy_async (folder, into, name, TRUE,
2284 transfer_folder_status_cb,
2286 g_object_unref (into);
2288 g_object_unref (into);
2295 /* Set status failed and set an error */
2296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2297 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2298 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2299 _("FIXME: unable to rename"));
2302 user_callback (self, NULL, user_data);
2304 /* Notify about operation end */
2305 modest_mail_operation_notify_end (self);
2308 /* ******************************************************************* */
2309 /* ************************** MSG ACTIONS ************************* */
2310 /* ******************************************************************* */
2313 modest_mail_operation_get_msg (ModestMailOperation *self,
2315 gboolean progress_feedback,
2316 GetMsgAsyncUserCallback user_callback,
2319 GetMsgInfo *helper = NULL;
2321 ModestMailOperationPrivate *priv;
2323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2324 g_return_if_fail (TNY_IS_HEADER (header));
2326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2327 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2331 /* Check memory low */
2332 if (_check_memory_low (self)) {
2334 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2335 modest_mail_operation_notify_end (self);
2339 /* Get account and set it into mail_operation */
2340 folder = tny_header_get_folder (header);
2341 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2343 /* Check for cached messages */
2344 if (progress_feedback) {
2345 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2346 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2348 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2350 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2353 /* Create the helper */
2354 helper = g_slice_new0 (GetMsgInfo);
2355 helper->header = g_object_ref (header);
2356 helper->mail_op = g_object_ref (self);
2357 helper->user_callback = user_callback;
2358 helper->user_data = user_data;
2359 helper->destroy_notify = NULL;
2360 helper->last_total_bytes = 0;
2361 helper->sum_total_bytes = 0;
2362 helper->total_bytes = tny_header_get_message_size (header);
2363 helper->more_msgs = NULL;
2365 modest_mail_operation_notify_start (self);
2367 /* notify about the start of the operation */
2368 ModestMailOperationState *state;
2369 state = modest_mail_operation_clone_state (self);
2372 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2374 g_slice_free (ModestMailOperationState, state);
2376 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2378 g_object_unref (G_OBJECT (folder));
2382 get_msg_status_cb (GObject *obj,
2386 GetMsgInfo *helper = NULL;
2388 g_return_if_fail (status != NULL);
2390 /* Show only the status information we want */
2391 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2394 helper = (GetMsgInfo *) user_data;
2395 g_return_if_fail (helper != NULL);
2397 /* Notify progress */
2398 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2399 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2403 get_msg_async_cb (TnyFolder *folder,
2409 GetMsgInfo *info = NULL;
2410 ModestMailOperationPrivate *priv = NULL;
2413 info = (GetMsgInfo *) user_data;
2415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2418 if (info->more_msgs) {
2419 tny_iterator_next (info->more_msgs);
2420 finished = (tny_iterator_is_done (info->more_msgs));
2422 finished = (priv->done == priv->total) ? TRUE : FALSE;
2425 /* If canceled by the user, ignore the error given by Tinymail */
2429 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2431 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2433 priv->error = g_error_copy ((const GError *) err);
2434 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2437 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2438 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2441 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2442 /* Set the success status before calling the user callback */
2443 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2447 /* Call the user callback */
2448 if (info->user_callback)
2449 info->user_callback (info->mail_op, info->header, canceled,
2450 msg, err, info->user_data);
2452 /* Notify about operation end if this is the last callback */
2454 /* Free user data */
2455 if (info->destroy_notify)
2456 info->destroy_notify (info->user_data);
2458 /* Notify about operation end */
2459 modest_mail_operation_notify_end (info->mail_op);
2462 if (info->more_msgs)
2463 g_object_unref (info->more_msgs);
2464 g_object_unref (info->header);
2465 g_object_unref (info->mail_op);
2466 g_slice_free (GetMsgInfo, info);
2467 } else if (info->more_msgs) {
2468 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2469 TnyFolder *folder = tny_header_get_folder (header);
2471 g_object_unref (info->header);
2472 info->header = g_object_ref (header);
2474 /* Retrieve the next message */
2475 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2477 g_object_unref (header);
2478 g_object_unref (folder);
2480 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2485 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2486 TnyList *header_list,
2487 GetMsgAsyncUserCallback user_callback,
2489 GDestroyNotify notify)
2491 ModestMailOperationPrivate *priv = NULL;
2493 TnyIterator *iter = NULL;
2494 gboolean has_uncached_messages;
2496 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2498 /* Init mail operation */
2499 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2500 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2502 priv->total = tny_list_get_length(header_list);
2504 /* Check memory low */
2505 if (_check_memory_low (self)) {
2506 if (user_callback) {
2507 TnyHeader *header = NULL;
2510 if (tny_list_get_length (header_list) > 0) {
2511 iter = tny_list_create_iterator (header_list);
2512 header = (TnyHeader *) tny_iterator_get_current (iter);
2513 g_object_unref (iter);
2515 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2517 g_object_unref (header);
2521 /* Notify about operation end */
2522 modest_mail_operation_notify_end (self);
2526 /* Check uncached messages */
2527 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2528 !has_uncached_messages && !tny_iterator_is_done (iter);
2529 tny_iterator_next (iter)) {
2532 header = (TnyHeader *) tny_iterator_get_current (iter);
2533 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2534 has_uncached_messages = TRUE;
2535 g_object_unref (header);
2537 g_object_unref (iter);
2538 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2540 /* Get account and set it into mail_operation */
2541 if (tny_list_get_length (header_list) >= 1) {
2542 TnyIterator *iterator = tny_list_create_iterator (header_list);
2543 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2545 TnyFolder *folder = tny_header_get_folder (header);
2547 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2548 g_object_unref (folder);
2550 g_object_unref (header);
2552 g_object_unref (iterator);
2555 msg_list_size = compute_message_list_size (header_list, 0);
2557 modest_mail_operation_notify_start (self);
2558 iter = tny_list_create_iterator (header_list);
2559 if (!tny_iterator_is_done (iter)) {
2560 /* notify about the start of the operation */
2561 ModestMailOperationState *state;
2562 state = modest_mail_operation_clone_state (self);
2565 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2568 GetMsgInfo *msg_info = NULL;
2569 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2570 TnyFolder *folder = tny_header_get_folder (header);
2572 /* Create the message info */
2573 msg_info = g_slice_new0 (GetMsgInfo);
2574 msg_info->mail_op = g_object_ref (self);
2575 msg_info->header = g_object_ref (header);
2576 msg_info->more_msgs = g_object_ref (iter);
2577 msg_info->user_callback = user_callback;
2578 msg_info->user_data = user_data;
2579 msg_info->destroy_notify = notify;
2580 msg_info->last_total_bytes = 0;
2581 msg_info->sum_total_bytes = 0;
2582 msg_info->total_bytes = msg_list_size;
2584 /* The callback will call it per each header */
2585 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2587 /* Free and go on */
2588 g_object_unref (header);
2589 g_object_unref (folder);
2590 g_slice_free (ModestMailOperationState, state);
2592 g_object_unref (iter);
2597 remove_msgs_async_cb (TnyFolder *folder,
2602 gboolean expunge, leave_on_server;
2603 const gchar *account_name;
2605 TnyAccount *account;
2606 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2607 ModestMailOperation *self;
2608 ModestMailOperationPrivate *priv;
2610 self = (ModestMailOperation *) user_data;
2611 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2613 if (canceled || err) {
2614 /* If canceled by the user, ignore the error given by Tinymail */
2616 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2619 priv->error = g_error_copy ((const GError *) err);
2620 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2623 modest_mail_operation_notify_end (self);
2624 g_object_unref (self);
2628 account = tny_folder_get_account (folder);
2629 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2631 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2633 proto = tny_account_get_proto (account);
2634 g_object_unref (account);
2637 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2639 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2640 modest_tny_folder_is_remote_folder (folder) == FALSE)
2646 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2651 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2653 gboolean remove_to_trash /*ignored*/)
2655 TnyFolder *folder = NULL;
2656 ModestMailOperationPrivate *priv;
2657 TnyIterator *iter = NULL;
2658 TnyHeader *header = NULL;
2659 TnyList *remove_headers = NULL;
2660 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2662 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2663 g_return_if_fail (TNY_IS_LIST (headers));
2665 if (remove_to_trash)
2666 g_warning ("remove to trash is not implemented");
2668 if (tny_list_get_length(headers) == 0) {
2669 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2670 goto cleanup; /* nothing to do */
2673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2674 remove_headers = g_object_ref(headers);
2676 /* Get folder from first header and sync it */
2677 iter = tny_list_create_iterator (headers);
2678 header = TNY_HEADER (tny_iterator_get_current (iter));
2680 folder = tny_header_get_folder (header);
2681 if (!TNY_IS_FOLDER(folder)) {
2682 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2686 /* Don't remove messages that are being sent */
2687 if (modest_tny_folder_is_local_folder (folder)) {
2688 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2690 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2691 TnyTransportAccount *traccount = NULL;
2692 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2693 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2695 ModestTnySendQueueStatus status;
2696 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2698 if (TNY_IS_SEND_QUEUE (send_queue)) {
2699 TnyIterator *iter = tny_list_create_iterator(headers);
2700 g_object_unref(remove_headers);
2701 remove_headers = TNY_LIST(tny_simple_list_new());
2702 while (!tny_iterator_is_done(iter)) {
2704 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2705 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2706 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2707 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2708 tny_list_append(remove_headers, G_OBJECT(hdr));
2710 g_object_unref(hdr);
2712 tny_iterator_next(iter);
2714 g_object_unref(iter);
2716 g_object_unref(traccount);
2720 /* Get account and set it into mail_operation */
2721 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2722 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2723 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2725 /* remove message from folder */
2726 modest_mail_operation_notify_start (self);
2727 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2728 NULL, g_object_ref (self));
2732 g_object_unref (remove_headers);
2734 g_object_unref (header);
2736 g_object_unref (iter);
2738 g_object_unref (folder);
2742 notify_progress_of_multiple_messages (ModestMailOperation *self,
2744 gint *last_total_bytes,
2745 gint *sum_total_bytes,
2747 gboolean increment_done)
2749 ModestMailOperationPrivate *priv;
2750 ModestMailOperationState *state;
2751 gboolean is_num_bytes = FALSE;
2753 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2755 /* We know that tinymail sends us information about
2756 * transferred bytes with this particular message
2758 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2759 * I just added the 'if' so we don't get runtime warning)
2761 if (status->message)
2762 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2764 state = modest_mail_operation_clone_state (self);
2765 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2766 /* We know that we're in a different message when the
2767 total number of bytes to transfer is different. Of
2768 course it could fail if we're transferring messages
2769 of the same size, but this is a workarround */
2770 if (status->of_total != *last_total_bytes) {
2771 /* We need to increment the done when there is
2772 no information about each individual
2773 message, we need to do this in message
2774 transfers, and we don't do it for getting
2778 *sum_total_bytes += *last_total_bytes;
2779 *last_total_bytes = status->of_total;
2781 state->bytes_done += status->position + *sum_total_bytes;
2782 state->bytes_total = total_bytes;
2784 /* Notify the status change. Only notify about changes
2785 referred to bytes */
2786 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2790 g_slice_free (ModestMailOperationState, state);
2794 transfer_msgs_status_cb (GObject *obj,
2798 XFerMsgsAsyncHelper *helper;
2800 g_return_if_fail (status != NULL);
2802 /* Show only the status information we want */
2803 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2806 helper = (XFerMsgsAsyncHelper *) user_data;
2807 g_return_if_fail (helper != NULL);
2809 /* Notify progress */
2810 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2811 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2815 transfer_msgs_sync_folder_cb (TnyFolder *self,
2820 XFerMsgsAsyncHelper *helper;
2821 /* We don't care here about the results of the
2823 helper = (XFerMsgsAsyncHelper *) user_data;
2825 /* Notify about operation end */
2826 modest_mail_operation_notify_end (helper->mail_op);
2828 /* If user defined callback function was defined, call it */
2829 if (helper->user_callback)
2830 helper->user_callback (helper->mail_op, helper->user_data);
2833 if (helper->more_msgs)
2834 g_object_unref (helper->more_msgs);
2835 if (helper->headers)
2836 g_object_unref (helper->headers);
2837 if (helper->dest_folder)
2838 g_object_unref (helper->dest_folder);
2839 if (helper->mail_op)
2840 g_object_unref (helper->mail_op);
2841 g_slice_free (XFerMsgsAsyncHelper, helper);
2845 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2847 XFerMsgsAsyncHelper *helper;
2848 ModestMailOperation *self;
2849 ModestMailOperationPrivate *priv;
2850 gboolean finished = TRUE;
2852 helper = (XFerMsgsAsyncHelper *) user_data;
2853 self = helper->mail_op;
2855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2858 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2860 priv->error = g_error_copy (err);
2862 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2863 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2864 if (helper->more_msgs) {
2865 /* We'll transfer the next message in the list */
2866 tny_iterator_next (helper->more_msgs);
2867 if (!tny_iterator_is_done (helper->more_msgs)) {
2868 GObject *next_header;
2869 g_object_unref (helper->headers);
2870 helper->headers = tny_simple_list_new ();
2871 next_header = tny_iterator_get_current (helper->more_msgs);
2872 tny_list_append (helper->headers, next_header);
2873 g_object_unref (next_header);
2879 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2884 /* Synchronize the source folder contents. This should
2885 be done by tinymail but the camel_folder_sync it's
2886 actually disabled in transfer_msgs_thread_clean
2887 because it's supposed to cause hangs */
2888 tny_folder_sync_async (folder, helper->delete,
2889 transfer_msgs_sync_folder_cb,
2892 /* Transfer more messages */
2893 tny_folder_transfer_msgs_async (folder,
2895 helper->dest_folder,
2898 transfer_msgs_status_cb,
2903 /* Computes the size of the messages the headers in the list belongs
2904 to. If num_elements is different from 0 then it only takes into
2905 account the first num_elements for the calculation */
2907 compute_message_list_size (TnyList *headers,
2911 guint size = 0, element = 0;
2913 /* If num_elements is not valid then take all into account */
2914 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
2915 num_elements = tny_list_get_length (headers);
2917 iter = tny_list_create_iterator (headers);
2918 while (!tny_iterator_is_done (iter) && element < num_elements) {
2919 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2920 size += tny_header_get_message_size (header);
2921 g_object_unref (header);
2922 tny_iterator_next (iter);
2925 g_object_unref (iter);
2931 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2934 gboolean delete_original,
2935 XferMsgsAsyncUserCallback user_callback,
2938 ModestMailOperationPrivate *priv = NULL;
2939 TnyIterator *iter = NULL;
2940 TnyFolder *src_folder = NULL;
2941 XFerMsgsAsyncHelper *helper = NULL;
2942 TnyHeader *header = NULL;
2943 ModestTnyFolderRules rules = 0;
2944 TnyAccount *dst_account = NULL;
2945 gboolean leave_on_server;
2946 ModestMailOperationState *state;
2948 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2949 g_return_if_fail (headers && TNY_IS_LIST (headers));
2950 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2952 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2953 priv->total = tny_list_get_length (headers);
2955 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2956 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2958 /* Apply folder rules */
2959 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2960 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2961 /* Set status failed and set an error */
2962 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2963 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2964 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2965 _CS("ckct_ib_unable_to_paste_here"));
2966 /* Notify the queue */
2967 modest_mail_operation_notify_end (self);
2971 /* Get source folder */
2972 iter = tny_list_create_iterator (headers);
2973 header = TNY_HEADER (tny_iterator_get_current (iter));
2975 src_folder = tny_header_get_folder (header);
2976 g_object_unref (header);
2978 g_object_unref (iter);
2980 if (src_folder == NULL) {
2981 /* Notify the queue */
2982 modest_mail_operation_notify_end (self);
2984 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2989 /* Check folder source and destination */
2990 if (src_folder == folder) {
2991 /* Set status failed and set an error */
2992 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2993 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2994 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2995 _("mail_in_ui_folder_copy_target_error"));
2997 /* Notify the queue */
2998 modest_mail_operation_notify_end (self);
3001 g_object_unref (src_folder);
3005 /* Create the helper */
3006 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3007 helper->mail_op = g_object_ref(self);
3008 helper->dest_folder = g_object_ref(folder);
3009 helper->user_callback = user_callback;
3010 helper->user_data = user_data;
3011 helper->last_total_bytes = 0;
3012 helper->sum_total_bytes = 0;
3013 helper->total_bytes = compute_message_list_size (headers, 0);
3015 /* Get account and set it into mail_operation */
3016 priv->account = modest_tny_folder_get_account (src_folder);
3017 dst_account = modest_tny_folder_get_account (folder);
3019 if (priv->account == dst_account) {
3020 /* Transfer all messages at once using the fast
3021 * method. Note that depending on the server this
3022 * might not be that fast, and might not be
3023 * user-cancellable either */
3024 helper->headers = g_object_ref (headers);
3025 helper->more_msgs = NULL;
3027 /* Transfer messages one by one so the user can cancel
3030 helper->headers = tny_simple_list_new ();
3031 helper->more_msgs = tny_list_create_iterator (headers);
3032 hdr = tny_iterator_get_current (helper->more_msgs);
3033 tny_list_append (helper->headers, hdr);
3034 g_object_unref (hdr);
3037 /* If leave_on_server is set to TRUE then don't use
3038 delete_original, we always pass FALSE. This is because
3039 otherwise tinymail will try to sync the source folder and
3040 this could cause an error if we're offline while
3041 transferring an already downloaded message from a POP
3043 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
3044 MODEST_PROTOCOL_STORE_POP) {
3045 const gchar *account_name;
3047 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3048 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3051 leave_on_server = FALSE;
3054 /* Do not delete messages if leave on server is TRUE */
3055 helper->delete = (leave_on_server) ? FALSE : delete_original;
3057 modest_mail_operation_notify_start (self);
3059 /* Start notifying progress */
3060 state = modest_mail_operation_clone_state (self);
3063 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3064 g_slice_free (ModestMailOperationState, state);
3066 tny_folder_transfer_msgs_async (src_folder,
3071 transfer_msgs_status_cb,
3073 g_object_unref (src_folder);
3074 g_object_unref (dst_account);
3079 on_refresh_folder (TnyFolder *folder,
3084 RefreshAsyncHelper *helper = NULL;
3085 ModestMailOperation *self = NULL;
3086 ModestMailOperationPrivate *priv = NULL;
3088 helper = (RefreshAsyncHelper *) user_data;
3089 self = helper->mail_op;
3090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3092 g_return_if_fail(priv!=NULL);
3095 priv->error = g_error_copy (error);
3096 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3101 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3102 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3103 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3104 _("Error trying to refresh the contents of %s"),
3105 tny_folder_get_name (folder));
3109 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3112 /* Call user defined callback, if it exists */
3113 if (helper->user_callback) {
3115 /* This is not a GDK lock because we are a Tinymail callback and
3116 * Tinymail already acquires the Gdk lock */
3117 helper->user_callback (self, folder, helper->user_data);
3121 g_slice_free (RefreshAsyncHelper, helper);
3123 /* Notify about operation end */
3124 modest_mail_operation_notify_end (self);
3125 g_object_unref(self);
3129 on_refresh_folder_status_update (GObject *obj,
3133 RefreshAsyncHelper *helper = NULL;
3134 ModestMailOperation *self = NULL;
3135 ModestMailOperationPrivate *priv = NULL;
3136 ModestMailOperationState *state;
3138 g_return_if_fail (user_data != NULL);
3139 g_return_if_fail (status != NULL);
3141 /* Show only the status information we want */
3142 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3145 helper = (RefreshAsyncHelper *) user_data;
3146 self = helper->mail_op;
3147 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3149 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3151 priv->done = status->position;
3152 priv->total = status->of_total;
3154 state = modest_mail_operation_clone_state (self);
3156 /* This is not a GDK lock because we are a Tinymail callback and
3157 * Tinymail already acquires the Gdk lock */
3158 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3160 g_slice_free (ModestMailOperationState, state);
3164 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3166 RefreshAsyncUserCallback user_callback,
3169 ModestMailOperationPrivate *priv = NULL;
3170 RefreshAsyncHelper *helper = NULL;
3172 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3174 /* Check memory low */
3175 if (_check_memory_low (self)) {
3177 user_callback (self, folder, user_data);
3178 /* Notify about operation end */
3179 modest_mail_operation_notify_end (self);
3183 /* Get account and set it into mail_operation */
3184 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3185 priv->account = modest_tny_folder_get_account (folder);
3186 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3188 /* Create the helper */
3189 helper = g_slice_new0 (RefreshAsyncHelper);
3190 helper->mail_op = g_object_ref(self);
3191 helper->user_callback = user_callback;
3192 helper->user_data = user_data;
3194 modest_mail_operation_notify_start (self);
3196 /* notify that the operation was started */
3197 ModestMailOperationState *state;
3198 state = modest_mail_operation_clone_state (self);
3201 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3203 g_slice_free (ModestMailOperationState, state);
3205 tny_folder_refresh_async (folder,
3207 on_refresh_folder_status_update,
3212 run_queue_stop (ModestTnySendQueue *queue,
3213 ModestMailOperation *self)
3215 ModestMailOperationPrivate *priv;
3217 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3218 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3219 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3221 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3223 modest_mail_operation_notify_end (self);
3224 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3225 g_object_unref (self);
3229 modest_mail_operation_run_queue (ModestMailOperation *self,
3230 ModestTnySendQueue *queue)
3232 ModestMailOperationPrivate *priv;
3234 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3235 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3238 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3239 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3240 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3242 modest_mail_operation_notify_start (self);
3243 g_object_ref (self);
3244 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3248 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3250 ModestMailOperation *self = (ModestMailOperation *) userdata;
3251 ModestMailOperationPrivate *priv;
3253 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3254 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3255 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3257 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3259 modest_mail_operation_notify_end (self);
3260 g_object_unref (self);
3264 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3266 ModestMailOperationPrivate *priv;
3268 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3269 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3272 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3274 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3275 priv->account = NULL;
3276 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3278 modest_mail_operation_notify_start (self);
3279 g_object_ref (self);
3280 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3284 sync_folder_finish_callback (TnyFolder *self,
3290 ModestMailOperation *mail_op;
3291 ModestMailOperationPrivate *priv;
3293 mail_op = (ModestMailOperation *) user_data;
3294 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3296 /* If canceled by the user, ignore the error given by Tinymail */
3298 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3300 /* If the operation was a sync then the status is
3301 failed, but if it's part of another operation then
3302 just set it as finished with errors */
3303 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3304 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3306 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3307 priv->error = g_error_copy ((const GError *) err);
3308 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3310 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3313 modest_mail_operation_notify_end (mail_op);
3314 g_object_unref (mail_op);
3318 modest_mail_operation_sync_folder (ModestMailOperation *self,
3319 TnyFolder *folder, gboolean expunge)
3321 ModestMailOperationPrivate *priv;
3323 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3324 g_return_if_fail (TNY_IS_FOLDER (folder));
3325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3327 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3328 priv->account = modest_tny_folder_get_account (folder);
3329 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3331 modest_mail_operation_notify_start (self);
3332 g_object_ref (self);
3333 tny_folder_sync_async (folder, expunge,
3334 (TnyFolderCallback) sync_folder_finish_callback,
3339 modest_mail_operation_notify_start (ModestMailOperation *self)
3341 ModestMailOperationPrivate *priv = NULL;
3343 g_return_if_fail (self);
3345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3347 /* Ensure that all the fields are filled correctly */
3348 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3350 /* Notify the observers about the mail operation. We do not
3351 wrapp this emission because we assume that this function is
3352 always called from within the main lock */
3353 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3358 * It's used by the mail operation queue to notify the observers
3359 * attached to that signal that the operation finished. We need to use
3360 * that because tinymail does not give us the progress of a given
3361 * operation when it finishes (it directly calls the operation
3365 modest_mail_operation_notify_end (ModestMailOperation *self)
3367 ModestMailOperationPrivate *priv = NULL;
3369 g_return_if_fail (self);
3371 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3373 /* Notify the observers about the mail operation end. We do
3374 not wrapp this emission because we assume that this
3375 function is always called from within the main lock */
3376 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3378 /* Remove the error user data */
3379 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3380 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3384 modest_mail_operation_get_account (ModestMailOperation *self)
3386 ModestMailOperationPrivate *priv = NULL;
3388 g_return_val_if_fail (self, NULL);
3390 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3392 return (priv->account) ? g_object_ref (priv->account) : NULL;
3396 modest_mail_operation_noop (ModestMailOperation *self)
3398 ModestMailOperationPrivate *priv = NULL;
3400 g_return_if_fail (self);
3402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3403 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3404 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3408 /* This mail operation does nothing actually */
3409 modest_mail_operation_notify_start (self);
3410 modest_mail_operation_notify_end (self);
3415 modest_mail_operation_to_string (ModestMailOperation *self)
3417 const gchar *type, *status, *account_id;
3418 ModestMailOperationPrivate *priv = NULL;
3420 g_return_val_if_fail (self, NULL);
3422 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3424 /* new operations don't have anything interesting */
3425 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3426 return g_strdup_printf ("%p <new operation>", self);
3428 switch (priv->op_type) {
3429 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3430 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3431 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3432 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3433 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3434 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3435 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3436 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3437 default: type = "UNEXPECTED"; break;
3440 switch (priv->status) {
3441 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3442 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3443 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3444 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3445 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3446 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3447 default: status= "UNEXPECTED"; break;
3450 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3452 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3453 priv->done, priv->total,
3454 priv->error && priv->error->message ? priv->error->message : "");
3458 * Once the mail operations were objects this will be no longer
3459 * needed. I don't like it, but we need it for the moment
3462 _check_memory_low (ModestMailOperation *mail_op)
3464 if (modest_platform_check_memory_low (NULL, FALSE)) {
3465 ModestMailOperationPrivate *priv;
3467 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3468 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3469 g_set_error (&(priv->error),
3470 MODEST_MAIL_OPERATION_ERROR,
3471 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3472 "Not enough memory to complete the operation");