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);
100 static guint compute_message_array_size (GPtrArray *headers);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 enum _ModestMailOperationSignals
112 PROGRESS_CHANGED_SIGNAL,
113 OPERATION_STARTED_SIGNAL,
114 OPERATION_FINISHED_SIGNAL,
118 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
119 struct _ModestMailOperationPrivate {
125 ErrorCheckingUserCallback error_checking;
126 gpointer error_checking_user_data;
127 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
128 ModestMailOperationStatus status;
129 ModestMailOperationTypeOperation op_type;
132 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
133 MODEST_TYPE_MAIL_OPERATION, \
134 ModestMailOperationPrivate))
136 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
137 priv->status = new_status;\
142 GetMsgAsyncUserCallback user_callback;
144 TnyIterator *more_msgs;
146 ModestMailOperation *mail_op;
147 GDestroyNotify destroy_notify;
148 gint last_total_bytes;
149 gint sum_total_bytes;
153 typedef struct _RefreshAsyncHelper {
154 ModestMailOperation *mail_op;
155 RefreshAsyncUserCallback user_callback;
157 } RefreshAsyncHelper;
159 typedef struct _XFerMsgsAsyncHelper
161 ModestMailOperation *mail_op;
163 TnyIterator *more_msgs;
164 TnyFolder *dest_folder;
165 XferMsgsAsyncUserCallback user_callback;
168 gint last_total_bytes;
169 gint sum_total_bytes;
171 } XFerMsgsAsyncHelper;
173 typedef struct _XFerFolderAsyncHelper
175 ModestMailOperation *mail_op;
176 XferFolderAsyncUserCallback user_callback;
178 } XFerFolderAsyncHelper;
180 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
184 static void modest_mail_operation_create_msg (ModestMailOperation *self,
185 const gchar *from, const gchar *to,
186 const gchar *cc, const gchar *bcc,
187 const gchar *subject, const gchar *plain_body,
188 const gchar *html_body, const GList *attachments_list,
189 const GList *images_list,
190 TnyHeaderFlags priority_flags,
191 ModestMailOperationCreateMsgCallback callback,
194 static gboolean idle_notify_queue (gpointer data);
197 ModestMailOperation *mail_op;
205 GList *attachments_list;
207 TnyHeaderFlags priority_flags;
208 ModestMailOperationCreateMsgCallback callback;
214 ModestMailOperation *mail_op;
216 ModestMailOperationCreateMsgCallback callback;
221 static GObjectClass *parent_class = NULL;
223 static guint signals[NUM_SIGNALS] = {0};
226 modest_mail_operation_get_type (void)
228 static GType my_type = 0;
230 static const GTypeInfo my_info = {
231 sizeof(ModestMailOperationClass),
232 NULL, /* base init */
233 NULL, /* base finalize */
234 (GClassInitFunc) modest_mail_operation_class_init,
235 NULL, /* class finalize */
236 NULL, /* class data */
237 sizeof(ModestMailOperation),
239 (GInstanceInitFunc) modest_mail_operation_init,
242 my_type = g_type_register_static (G_TYPE_OBJECT,
243 "ModestMailOperation",
250 modest_mail_operation_class_init (ModestMailOperationClass *klass)
252 GObjectClass *gobject_class;
253 gobject_class = (GObjectClass*) klass;
255 parent_class = g_type_class_peek_parent (klass);
256 gobject_class->finalize = modest_mail_operation_finalize;
258 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
261 * ModestMailOperation::progress-changed
262 * @self: the #MailOperation that emits the signal
263 * @user_data: user data set when the signal handler was connected
265 * Emitted when the progress of a mail operation changes
267 signals[PROGRESS_CHANGED_SIGNAL] =
268 g_signal_new ("progress-changed",
269 G_TYPE_FROM_CLASS (gobject_class),
271 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
273 g_cclosure_marshal_VOID__POINTER,
274 G_TYPE_NONE, 1, G_TYPE_POINTER);
278 * This signal is issued whenever a mail operation starts, and
279 * starts mean when the tinymail operation is issued. This
280 * means that it could happen that something wrong happens and
281 * the tinymail function is never called. In this situation a
282 * operation-finished will be issued without any
285 signals[OPERATION_STARTED_SIGNAL] =
286 g_signal_new ("operation-started",
287 G_TYPE_FROM_CLASS (gobject_class),
289 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
291 g_cclosure_marshal_VOID__VOID,
296 * This signal is issued whenever a mail operation
297 * finishes. Note that this signal could be issued without any
298 * previous "operation-started" signal, because this last one
299 * is only issued when the tinymail operation is successfully
302 signals[OPERATION_FINISHED_SIGNAL] =
303 g_signal_new ("operation-finished",
304 G_TYPE_FROM_CLASS (gobject_class),
306 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
308 g_cclosure_marshal_VOID__VOID,
313 modest_mail_operation_init (ModestMailOperation *obj)
315 ModestMailOperationPrivate *priv;
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
319 priv->account = NULL;
320 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
321 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
326 priv->error_checking = NULL;
327 priv->error_checking_user_data = NULL;
331 modest_mail_operation_finalize (GObject *obj)
333 ModestMailOperationPrivate *priv;
335 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
340 g_error_free (priv->error);
344 g_object_unref (priv->source);
348 g_object_unref (priv->account);
349 priv->account = NULL;
353 G_OBJECT_CLASS(parent_class)->finalize (obj);
357 modest_mail_operation_new (GObject *source)
359 ModestMailOperation *obj;
360 ModestMailOperationPrivate *priv;
362 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
366 priv->source = g_object_ref(source);
372 modest_mail_operation_new_with_error_handling (GObject *source,
373 ErrorCheckingUserCallback error_handler,
375 ErrorCheckingUserDataDestroyer error_handler_destroyer)
377 ModestMailOperation *obj;
378 ModestMailOperationPrivate *priv;
380 obj = modest_mail_operation_new (source);
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
383 g_return_val_if_fail (error_handler != NULL, obj);
384 priv->error_checking = error_handler;
385 priv->error_checking_user_data = user_data;
386 priv->error_checking_user_data_destroyer = error_handler_destroyer;
392 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
394 ModestMailOperationPrivate *priv;
396 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
399 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
401 /* Call the user callback */
402 if (priv->error_checking != NULL)
403 priv->error_checking (self, priv->error_checking_user_data);
407 ModestMailOperationTypeOperation
408 modest_mail_operation_get_type_operation (ModestMailOperation *self)
410 ModestMailOperationPrivate *priv;
412 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
413 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
417 return priv->op_type;
421 modest_mail_operation_is_mine (ModestMailOperation *self,
424 ModestMailOperationPrivate *priv;
426 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
430 if (priv->source == NULL) return FALSE;
432 return priv->source == me;
436 modest_mail_operation_get_source (ModestMailOperation *self)
438 ModestMailOperationPrivate *priv;
440 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
445 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
449 return (priv->source) ? g_object_ref (priv->source) : NULL;
452 ModestMailOperationStatus
453 modest_mail_operation_get_status (ModestMailOperation *self)
455 ModestMailOperationPrivate *priv;
457 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
458 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
459 MODEST_MAIL_OPERATION_STATUS_INVALID);
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
463 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
464 return MODEST_MAIL_OPERATION_STATUS_INVALID;
471 modest_mail_operation_get_error (ModestMailOperation *self)
473 ModestMailOperationPrivate *priv;
475 g_return_val_if_fail (self, NULL);
476 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
481 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
489 modest_mail_operation_cancel (ModestMailOperation *self)
491 ModestMailOperationPrivate *priv;
492 gboolean canceled = FALSE;
494 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
499 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
501 /* Cancel the mail operation */
502 g_return_val_if_fail (priv->account, FALSE);
503 tny_account_cancel (priv->account);
505 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
506 ModestTnySendQueue *queue;
507 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
510 /* Cancel the sending of the following next messages */
511 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
518 modest_mail_operation_get_task_done (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
522 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
530 modest_mail_operation_get_task_total (ModestMailOperation *self)
532 ModestMailOperationPrivate *priv;
534 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
542 modest_mail_operation_is_finished (ModestMailOperation *self)
544 ModestMailOperationPrivate *priv;
545 gboolean retval = FALSE;
547 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
550 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
552 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
553 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
554 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
555 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
565 * Creates an image of the current state of a mail operation, the
566 * caller must free it
568 static ModestMailOperationState *
569 modest_mail_operation_clone_state (ModestMailOperation *self)
571 ModestMailOperationState *state;
572 ModestMailOperationPrivate *priv;
574 /* FIXME: this should be fixed properly
576 * in some cases, priv was NULL, so checking here to
579 g_return_val_if_fail (self, NULL);
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
581 g_return_val_if_fail (priv, NULL);
586 state = g_slice_new (ModestMailOperationState);
588 state->status = priv->status;
589 state->op_type = priv->op_type;
590 state->done = priv->done;
591 state->total = priv->total;
592 state->finished = modest_mail_operation_is_finished (self);
593 state->bytes_done = 0;
594 state->bytes_total = 0;
599 /* ******************************************************************* */
600 /* ************************** SEND ACTIONS ************************* */
601 /* ******************************************************************* */
604 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
610 ModestMailOperationPrivate *priv;
611 ModestMailOperation *self;
613 self = MODEST_MAIL_OPERATION (user_data);
614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
616 if (cancelled || err)
620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
621 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
622 "Error adding a msg to the send queue\n");
623 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
625 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
628 modest_mail_operation_notify_end (self);
629 g_object_unref (self);
633 modest_mail_operation_send_mail (ModestMailOperation *self,
634 TnyTransportAccount *transport_account,
637 TnySendQueue *send_queue = NULL;
638 ModestMailOperationPrivate *priv;
640 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
641 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
642 g_return_if_fail (msg && TNY_IS_MSG (msg));
644 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
646 /* Get account and set it into mail_operation */
647 priv->account = g_object_ref (transport_account);
648 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
652 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
653 if (!TNY_IS_SEND_QUEUE(send_queue)) {
655 g_error_free (priv->error);
658 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
659 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
660 "modest: could not find send queue for account\n");
661 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
662 modest_mail_operation_notify_end (self);
664 modest_mail_operation_notify_start (self);
665 /* Add the msg to the queue. The callback will
666 finalize the mail operation */
667 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
668 NULL, g_object_ref (self));
669 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
676 idle_create_msg_cb (gpointer idle_data)
678 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
680 /* This is a GDK lock because we are an idle callback and
681 * info->callback can contain Gtk+ code */
683 gdk_threads_enter (); /* CHECKED */
684 info->callback (info->mail_op, info->msg, info->userdata);
686 g_object_unref (info->mail_op);
688 g_object_unref (info->msg);
689 g_slice_free (CreateMsgIdleInfo, info);
690 gdk_threads_leave (); /* CHECKED */
696 create_msg_thread (gpointer thread_data)
698 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
699 TnyMsg *new_msg = NULL;
700 ModestMailOperationPrivate *priv;
702 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
703 if (info->html_body == NULL) {
704 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
705 info->bcc, info->subject, info->plain_body,
706 info->attachments_list,
709 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
710 info->bcc, info->subject, info->html_body,
711 info->plain_body, info->attachments_list,
719 /* Set priority flags in message */
720 header = tny_msg_get_header (new_msg);
721 tny_header_set_flag (header, info->priority_flags);
723 /* Set attachment flags in message */
724 if (info->attachments_list != NULL)
725 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
727 g_object_unref (G_OBJECT(header));
729 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
731 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
732 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
733 "modest: failed to create a new msg\n");
741 g_free (info->plain_body);
742 g_free (info->html_body);
743 g_free (info->subject);
744 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
745 g_list_free (info->attachments_list);
746 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
747 g_list_free (info->images_list);
749 if (info->callback) {
750 CreateMsgIdleInfo *idle_info;
751 idle_info = g_slice_new0 (CreateMsgIdleInfo);
752 idle_info->mail_op = g_object_ref (info->mail_op);
753 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
754 idle_info->callback = info->callback;
755 idle_info->userdata = info->userdata;
756 g_idle_add (idle_create_msg_cb, idle_info);
758 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
761 g_object_unref (info->mail_op);
762 g_slice_free (CreateMsgInfo, info);
763 if (new_msg) g_object_unref(new_msg);
769 modest_mail_operation_create_msg (ModestMailOperation *self,
770 const gchar *from, const gchar *to,
771 const gchar *cc, const gchar *bcc,
772 const gchar *subject, const gchar *plain_body,
773 const gchar *html_body,
774 const GList *attachments_list,
775 const GList *images_list,
776 TnyHeaderFlags priority_flags,
777 ModestMailOperationCreateMsgCallback callback,
780 CreateMsgInfo *info = NULL;
782 info = g_slice_new0 (CreateMsgInfo);
783 info->mail_op = g_object_ref (self);
785 info->from = g_strdup (from);
786 info->to = g_strdup (to);
787 info->cc = g_strdup (cc);
788 info->bcc = g_strdup (bcc);
789 info->subject = g_strdup (subject);
790 info->plain_body = g_strdup (plain_body);
791 info->html_body = g_strdup (html_body);
792 info->attachments_list = g_list_copy ((GList *) attachments_list);
793 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
794 info->images_list = g_list_copy ((GList *) images_list);
795 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
796 info->priority_flags = priority_flags;
798 info->callback = callback;
799 info->userdata = userdata;
801 g_thread_create (create_msg_thread, info, FALSE, NULL);
806 TnyTransportAccount *transport_account;
811 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
815 ModestMailOperationPrivate *priv = NULL;
816 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
817 TnyFolder *draft_folder = NULL;
818 TnyFolder *outbox_folder = NULL;
819 TnyHeader *header = NULL;
821 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 modest_mail_operation_notify_end (self);
829 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
831 modest_mail_operation_notify_end (self);
835 /* Call mail operation */
836 modest_mail_operation_send_mail (self, info->transport_account, msg);
838 if (info->draft_msg != NULL) {
839 TnyList *tmp_headers = NULL;
840 TnyFolder *folder = NULL;
841 TnyFolder *src_folder = NULL;
842 TnyFolderType folder_type;
843 TnyTransportAccount *transport_account = NULL;
845 /* To remove the old mail from its source folder, we need to get the
846 * transport account of the original draft message (the transport account
847 * might have been changed by the user) */
848 header = tny_msg_get_header (info->draft_msg);
849 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
850 modest_runtime_get_account_store(), header);
851 if (transport_account == NULL)
852 transport_account = g_object_ref(info->transport_account);
853 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
854 TNY_FOLDER_TYPE_DRAFTS);
855 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
856 TNY_FOLDER_TYPE_OUTBOX);
857 g_object_unref(transport_account);
860 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
864 if (!outbox_folder) {
865 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
870 folder = tny_msg_get_folder (info->draft_msg);
871 if (folder == NULL) goto end;
872 folder_type = modest_tny_folder_guess_folder_type (folder);
874 if (folder_type == TNY_FOLDER_TYPE_INVALID)
875 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
877 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
878 src_folder = outbox_folder;
880 src_folder = draft_folder;
882 /* Note: This can fail (with a warning) if the message is not really already in a folder,
883 * because this function requires it to have a UID. */
884 tmp_headers = tny_simple_list_new ();
885 tny_list_append (tmp_headers, (GObject*) header);
886 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
887 g_object_unref (tmp_headers);
888 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
890 g_object_unref (folder);
895 g_object_unref (header);
897 g_object_unref (info->draft_msg);
899 g_object_unref (draft_folder);
901 g_object_unref (outbox_folder);
902 if (info->transport_account)
903 g_object_unref (info->transport_account);
904 g_slice_free (SendNewMailInfo, info);
908 modest_mail_operation_send_new_mail (ModestMailOperation *self,
909 TnyTransportAccount *transport_account,
911 const gchar *from, const gchar *to,
912 const gchar *cc, const gchar *bcc,
913 const gchar *subject, const gchar *plain_body,
914 const gchar *html_body,
915 const GList *attachments_list,
916 const GList *images_list,
917 TnyHeaderFlags priority_flags)
919 ModestMailOperationPrivate *priv = NULL;
920 SendNewMailInfo *info;
922 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
923 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
926 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
927 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
928 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
930 /* Check parametters */
932 /* Set status failed and set an error */
933 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
934 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
935 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
936 _("Error trying to send a mail. You need to set at least one recipient"));
939 info = g_slice_new0 (SendNewMailInfo);
940 info->transport_account = transport_account;
941 if (transport_account)
942 g_object_ref (transport_account);
943 info->draft_msg = draft_msg;
945 g_object_ref (draft_msg);
948 modest_mail_operation_notify_start (self);
949 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
950 attachments_list, images_list, priority_flags,
951 modest_mail_operation_send_new_mail_cb, info);
957 TnyTransportAccount *transport_account;
959 SaveToDraftstCallback callback;
963 ModestMailOperation *mailop;
964 } SaveToDraftsAddMsgInfo;
967 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
972 ModestMailOperationPrivate *priv = NULL;
973 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
974 GError *io_error = NULL;
976 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
978 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
979 io_error = priv->error;
983 g_warning ("%s: priv->error != NULL", __FUNCTION__);
984 g_error_free(priv->error);
987 priv->error = (err == NULL) ? NULL : g_error_copy(err);
989 if ((!priv->error) && (info->draft_msg != NULL)) {
990 TnyHeader *header = tny_msg_get_header (info->draft_msg);
991 TnyFolder *src_folder = tny_header_get_folder (header);
993 /* Remove the old draft */
994 tny_folder_remove_msg (src_folder, header, NULL);
996 /* Synchronize to expunge and to update the msg counts */
997 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
998 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1000 g_object_unref (G_OBJECT(header));
1001 g_object_unref (G_OBJECT(src_folder));
1005 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1007 g_error_free (io_error);
1010 } else if (io_error) {
1011 priv->error = io_error;
1012 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1014 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1017 /* Call the user callback */
1019 info->callback (info->mailop, info->msg, info->user_data);
1021 if (info->transport_account)
1022 g_object_unref (G_OBJECT(info->transport_account));
1023 if (info->draft_msg)
1024 g_object_unref (G_OBJECT (info->draft_msg));
1026 g_object_unref (G_OBJECT(info->drafts));
1028 g_object_unref (G_OBJECT (info->msg));
1030 modest_mail_operation_notify_end (info->mailop);
1031 g_object_unref(info->mailop);
1032 g_slice_free (SaveToDraftsAddMsgInfo, info);
1037 TnyTransportAccount *transport_account;
1039 SaveToDraftstCallback callback;
1044 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1048 TnyFolder *drafts = NULL;
1049 ModestMailOperationPrivate *priv = NULL;
1050 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1052 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1055 if (!(priv->error)) {
1056 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1057 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1058 "modest: failed to create a new msg\n");
1061 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1062 TNY_FOLDER_TYPE_DRAFTS);
1063 if (!drafts && !(priv->error)) {
1064 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1065 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1066 "modest: failed to create a new msg\n");
1070 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1071 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1072 cb_info->transport_account = g_object_ref(info->transport_account);
1073 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1074 cb_info->callback = info->callback;
1075 cb_info->user_data = info->user_data;
1076 cb_info->drafts = g_object_ref(drafts);
1077 cb_info->msg = g_object_ref(msg);
1078 cb_info->mailop = g_object_ref(self);
1079 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1082 /* Call the user callback */
1083 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1085 info->callback (self, msg, info->user_data);
1086 modest_mail_operation_notify_end (self);
1090 g_object_unref (G_OBJECT(drafts));
1091 if (info->draft_msg)
1092 g_object_unref (G_OBJECT (info->draft_msg));
1093 if (info->transport_account)
1094 g_object_unref (G_OBJECT(info->transport_account));
1095 g_slice_free (SaveToDraftsInfo, info);
1099 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1100 TnyTransportAccount *transport_account,
1102 const gchar *from, const gchar *to,
1103 const gchar *cc, const gchar *bcc,
1104 const gchar *subject, const gchar *plain_body,
1105 const gchar *html_body,
1106 const GList *attachments_list,
1107 const GList *images_list,
1108 TnyHeaderFlags priority_flags,
1109 SaveToDraftstCallback callback,
1112 ModestMailOperationPrivate *priv = NULL;
1113 SaveToDraftsInfo *info = NULL;
1115 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1116 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1120 /* Get account and set it into mail_operation */
1121 priv->account = g_object_ref (transport_account);
1122 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1124 info = g_slice_new0 (SaveToDraftsInfo);
1125 info->transport_account = g_object_ref (transport_account);
1126 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1127 info->callback = callback;
1128 info->user_data = user_data;
1130 modest_mail_operation_notify_start (self);
1131 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1132 attachments_list, images_list, priority_flags,
1133 modest_mail_operation_save_to_drafts_cb, info);
1138 ModestMailOperation *mail_op;
1139 TnyMimePart *mime_part;
1141 GetMimePartSizeCallback callback;
1143 } GetMimePartSizeInfo;
1145 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1146 /* We use this folder observer to track the headers that have been
1147 * added to a folder */
1150 TnyList *new_headers;
1151 } InternalFolderObserver;
1154 GObjectClass parent;
1155 } InternalFolderObserverClass;
1157 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1159 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1160 internal_folder_observer,
1162 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1166 foreach_add_item (gpointer header, gpointer user_data)
1168 tny_list_prepend (TNY_LIST (user_data),
1169 g_object_ref (G_OBJECT (header)));
1172 /* This is the method that looks for new messages in a folder */
1174 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1176 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1178 TnyFolderChangeChanged changed;
1180 changed = tny_folder_change_get_changed (change);
1182 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1185 /* Get added headers */
1186 list = tny_simple_list_new ();
1187 tny_folder_change_get_added_headers (change, list);
1189 /* Add them to the folder observer */
1190 tny_list_foreach (list, foreach_add_item,
1191 derived->new_headers);
1193 g_object_unref (G_OBJECT (list));
1198 internal_folder_observer_init (InternalFolderObserver *self)
1200 self->new_headers = tny_simple_list_new ();
1203 internal_folder_observer_finalize (GObject *object)
1205 InternalFolderObserver *self;
1207 self = (InternalFolderObserver *) object;
1208 g_object_unref (self->new_headers);
1210 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1213 tny_folder_observer_init (TnyFolderObserverIface *iface)
1215 iface->update = internal_folder_observer_update;
1218 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1220 GObjectClass *object_class;
1222 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1223 object_class = (GObjectClass*) klass;
1224 object_class->finalize = internal_folder_observer_finalize;
1229 ModestMailOperation *mail_op;
1230 gchar *account_name;
1231 UpdateAccountCallback callback;
1236 TnyFolderObserver *inbox_observer;
1237 RetrieveAllCallback retrieve_all_cb;
1238 gboolean interactive;
1239 } UpdateAccountInfo;
1243 destroy_update_account_info (UpdateAccountInfo *info)
1245 g_free (info->account_name);
1246 g_object_unref (info->folders);
1247 g_object_unref (info->mail_op);
1248 g_slice_free (UpdateAccountInfo, info);
1252 update_account_get_msg_async_cb (TnyFolder *folder,
1258 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1260 /* Just delete the helper. Don't do anything with the new
1261 msg. There is also no need to check for errors */
1262 g_object_unref (msg_info->mail_op);
1263 g_object_unref (msg_info->header);
1264 g_slice_free (GetMsgInfo, msg_info);
1268 update_account_notify_user_and_free (UpdateAccountInfo *info,
1269 TnyList *new_headers)
1271 /* Set the account back to not busy */
1272 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1273 info->account_name, FALSE);
1277 info->callback (info->mail_op, new_headers, info->user_data);
1279 /* Mail operation end */
1280 modest_mail_operation_notify_end (info->mail_op);
1284 g_object_unref (new_headers);
1285 destroy_update_account_info (info);
1289 inbox_refreshed_cb (TnyFolder *inbox,
1294 UpdateAccountInfo *info;
1295 ModestMailOperationPrivate *priv;
1296 TnyIterator *new_headers_iter;
1297 GPtrArray *new_headers_array = NULL;
1298 gint max_size, retrieve_limit, i;
1299 ModestAccountMgr *mgr;
1300 ModestAccountRetrieveType retrieve_type;
1301 TnyList *new_headers = NULL;
1302 gboolean headers_only, ignore_limit;
1303 TnyTransportAccount *transport_account = NULL;
1305 info = (UpdateAccountInfo *) user_data;
1306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1307 mgr = modest_runtime_get_account_mgr ();
1309 /* Set the last updated as the current time, do it even if the inbox refresh failed */
1310 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1312 if (canceled || err) {
1313 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1315 priv->error = g_error_copy (err);
1317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1318 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1321 /* Notify the user about the error and then exit */
1322 update_account_notify_user_and_free (info, NULL);
1327 /* Try to send anyway */
1331 /* Get the message max size */
1332 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1333 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1335 max_size = G_MAXINT;
1337 max_size = max_size * KB;
1339 /* Create the new headers array. We need it to sort the
1340 new headers by date */
1341 new_headers_array = g_ptr_array_new ();
1342 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1343 while (!tny_iterator_is_done (new_headers_iter)) {
1344 TnyHeader *header = NULL;
1346 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1347 /* Apply per-message size limits */
1348 if (tny_header_get_message_size (header) < max_size)
1349 g_ptr_array_add (new_headers_array, g_object_ref (header));
1351 g_object_unref (header);
1352 tny_iterator_next (new_headers_iter);
1354 g_object_unref (new_headers_iter);
1355 tny_folder_remove_observer (inbox, info->inbox_observer);
1356 g_object_unref (info->inbox_observer);
1357 info->inbox_observer = NULL;
1359 if (new_headers_array->len == 0)
1362 /* Get per-account message amount retrieval limit */
1363 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1364 if (retrieve_limit == 0)
1365 retrieve_limit = G_MAXINT;
1367 /* Get per-account retrieval type */
1368 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1369 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1372 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1374 /* Ask the users if they want to retrieve all the messages
1375 even though the limit was exceeded */
1376 ignore_limit = FALSE;
1377 if (new_headers_array->len > retrieve_limit) {
1378 /* Ask the user if a callback has been specified and
1379 if the mail operation has a source (this means that
1380 was invoked by the user and not automatically by a
1382 if (info->retrieve_all_cb && priv->source)
1383 ignore_limit = info->retrieve_all_cb (priv->source,
1384 new_headers_array->len,
1388 if (!headers_only) {
1390 const gint msg_list_size = compute_message_array_size (new_headers_array);
1394 priv->total = new_headers_array->len;
1396 priv->total = MIN (new_headers_array->len, retrieve_limit);
1397 while (msg_num < priv->total) {
1398 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1399 TnyFolder *folder = tny_header_get_folder (header);
1400 GetMsgInfo *msg_info;
1402 /* Create the message info */
1403 msg_info = g_slice_new0 (GetMsgInfo);
1404 msg_info->mail_op = g_object_ref (info->mail_op);
1405 msg_info->header = g_object_ref (header);
1406 msg_info->total_bytes = msg_list_size;
1408 /* Get message in an async way */
1409 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1410 get_msg_status_cb, msg_info);
1412 g_object_unref (folder);
1418 /* Copy the headers to a list and free the array */
1419 new_headers = tny_simple_list_new ();
1420 for (i=0; i < new_headers_array->len; i++) {
1421 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1422 tny_list_append (new_headers, G_OBJECT (header));
1424 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1425 g_ptr_array_free (new_headers_array, FALSE);
1428 /* Get the transport account */
1429 transport_account = (TnyTransportAccount *)
1430 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1431 info->account_name);
1433 if (transport_account) {
1434 ModestTnySendQueue *send_queue;
1438 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1439 g_object_unref (transport_account);
1441 /* Get outbox folder */
1442 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1443 if (outbox) { /* this could fail in some cases */
1444 num_messages = tny_folder_get_all_count (outbox);
1445 g_object_unref (outbox);
1447 g_warning ("%s: could not get outbox", __FUNCTION__);
1451 if (num_messages != 0) {
1452 /* Reenable suspended items */
1453 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1456 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1457 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1462 /* Check if the operation was a success */
1464 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1466 /* Call the user callback and free */
1467 update_account_notify_user_and_free (info, new_headers);
1471 inbox_refresh_status_update (GObject *obj,
1475 UpdateAccountInfo *info = NULL;
1476 ModestMailOperation *self = NULL;
1477 ModestMailOperationPrivate *priv = NULL;
1478 ModestMailOperationState *state;
1480 g_return_if_fail (user_data != NULL);
1481 g_return_if_fail (status != NULL);
1483 /* Show only the status information we want */
1484 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1487 info = (UpdateAccountInfo *) user_data;
1488 self = info->mail_op;
1489 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1493 priv->done = status->position;
1494 priv->total = status->of_total;
1496 state = modest_mail_operation_clone_state (self);
1498 /* This is not a GDK lock because we are a Tinymail callback and
1499 * Tinymail already acquires the Gdk lock */
1500 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1502 g_slice_free (ModestMailOperationState, state);
1506 recurse_folders_async_cb (TnyFolderStore *folder_store,
1512 UpdateAccountInfo *info;
1513 ModestMailOperationPrivate *priv;
1515 info = (UpdateAccountInfo *) user_data;
1516 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1518 if (err || canceled) {
1519 /* If the error was previosly set by another callback
1520 don't set it again */
1522 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1524 priv->error = g_error_copy (err);
1526 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1527 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1531 /* We're not getting INBOX children if we don't want to poke all */
1532 TnyIterator *iter = tny_list_create_iterator (list);
1533 while (!tny_iterator_is_done (iter)) {
1534 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1536 /* Add to the list of all folders */
1537 tny_list_append (info->folders, (GObject *) folder);
1539 if (info->poke_all) {
1540 TnyList *folders = tny_simple_list_new ();
1541 /* Add pending call */
1542 info->pending_calls++;
1544 tny_folder_store_get_folders_async (folder, folders, NULL,
1545 recurse_folders_async_cb,
1547 g_object_unref (folders);
1550 g_object_unref (G_OBJECT (folder));
1552 tny_iterator_next (iter);
1554 g_object_unref (G_OBJECT (iter));
1557 /* Remove my own pending call */
1558 info->pending_calls--;
1560 /* This means that we have all the folders */
1561 if (info->pending_calls == 0) {
1562 TnyIterator *iter_all_folders;
1563 TnyFolder *inbox = NULL;
1565 /* If there was any error do not continue */
1567 update_account_notify_user_and_free (info, NULL);
1571 iter_all_folders = tny_list_create_iterator (info->folders);
1573 /* Do a poke status over all folders */
1574 while (!tny_iterator_is_done (iter_all_folders) &&
1575 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1576 TnyFolder *folder = NULL;
1578 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1580 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1581 /* Get a reference to the INBOX */
1582 inbox = g_object_ref (folder);
1584 /* Issue a poke status over the folder */
1586 tny_folder_poke_status (folder);
1589 /* Free and go to next */
1590 g_object_unref (folder);
1591 tny_iterator_next (iter_all_folders);
1593 g_object_unref (iter_all_folders);
1595 /* Refresh the INBOX */
1597 /* Refresh the folder. Our observer receives
1598 * the new emails during folder refreshes, so
1599 * we can use observer->new_headers
1601 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1602 tny_folder_add_observer (inbox, info->inbox_observer);
1604 /* Refresh the INBOX */
1605 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1606 g_object_unref (inbox);
1608 /* We could not perform the inbox refresh but
1609 we'll try to send mails anyway */
1610 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1616 modest_mail_operation_update_account (ModestMailOperation *self,
1617 const gchar *account_name,
1619 gboolean interactive,
1620 RetrieveAllCallback retrieve_all_cb,
1621 UpdateAccountCallback callback,
1624 UpdateAccountInfo *info = NULL;
1625 ModestMailOperationPrivate *priv = NULL;
1626 ModestTnyAccountStore *account_store = NULL;
1628 ModestMailOperationState *state;
1630 /* Init mail operation */
1631 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1634 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1635 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1637 /* Get the store account */
1638 account_store = modest_runtime_get_account_store ();
1640 modest_tny_account_store_get_server_account (account_store,
1642 TNY_ACCOUNT_TYPE_STORE);
1644 /* The above function could return NULL */
1645 if (!priv->account) {
1646 /* Check if the operation was a success */
1647 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1648 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1650 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1652 /* Call the user callback */
1654 callback (self, NULL, user_data);
1656 /* Notify about operation end */
1657 modest_mail_operation_notify_end (self);
1662 /* We have once seen priv->account getting finalized during this code,
1663 * therefore adding a reference (bug #82296) */
1665 g_object_ref (priv->account);
1667 /* Create the helper object */
1668 info = g_slice_new0 (UpdateAccountInfo);
1669 info->pending_calls = 1;
1670 info->folders = tny_simple_list_new ();
1671 info->mail_op = g_object_ref (self);
1672 info->poke_all = poke_all;
1673 info->interactive = interactive;
1674 info->account_name = g_strdup (account_name);
1675 info->callback = callback;
1676 info->user_data = user_data;
1677 info->retrieve_all_cb = retrieve_all_cb;
1679 /* Set account busy */
1680 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1681 modest_mail_operation_notify_start (self);
1683 /* notify about the start of the operation */
1684 state = modest_mail_operation_clone_state (self);
1688 /* Start notifying progress */
1689 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1690 g_slice_free (ModestMailOperationState, state);
1692 /* Get all folders and continue in the callback */
1693 folders = tny_simple_list_new ();
1694 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1696 recurse_folders_async_cb,
1698 g_object_unref (folders);
1700 g_object_unref (priv->account);
1705 * Used to notify the queue from the main
1706 * loop. We call it inside an idle call to achieve that
1709 idle_notify_queue (gpointer data)
1711 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1713 gdk_threads_enter ();
1714 modest_mail_operation_notify_end (mail_op);
1715 gdk_threads_leave ();
1716 g_object_unref (mail_op);
1722 compare_headers_by_date (gconstpointer a,
1725 TnyHeader **header1, **header2;
1726 time_t sent1, sent2;
1728 header1 = (TnyHeader **) a;
1729 header2 = (TnyHeader **) b;
1731 sent1 = tny_header_get_date_sent (*header1);
1732 sent2 = tny_header_get_date_sent (*header2);
1734 /* We want the most recent ones (greater time_t) at the
1743 /* ******************************************************************* */
1744 /* ************************** STORE ACTIONS ************************* */
1745 /* ******************************************************************* */
1748 ModestMailOperation *mail_op;
1749 CreateFolderUserCallback callback;
1755 create_folder_cb (TnyFolderStore *parent_folder,
1757 TnyFolder *new_folder,
1761 ModestMailOperationPrivate *priv;
1762 CreateFolderInfo *info;
1764 info = (CreateFolderInfo *) user_data;
1765 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1767 if (canceled || err) {
1768 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1770 priv->error = g_error_copy (err);
1772 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1773 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1776 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1779 /* The user will unref the new_folder */
1781 info->callback (info->mail_op, parent_folder,
1782 new_folder, info->user_data);
1784 /* Notify about operation end */
1785 modest_mail_operation_notify_end (info->mail_op);
1788 g_object_unref (info->mail_op);
1789 g_slice_free (CreateFolderInfo, info);
1793 modest_mail_operation_create_folder (ModestMailOperation *self,
1794 TnyFolderStore *parent,
1796 CreateFolderUserCallback callback,
1799 ModestMailOperationPrivate *priv;
1801 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1802 g_return_if_fail (name);
1804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1805 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1806 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1807 g_object_ref (parent) :
1808 modest_tny_folder_get_account (TNY_FOLDER (parent));
1810 /* Check for already existing folder */
1811 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1812 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1813 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1814 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1815 _CS("ckdg_ib_folder_already_exists"));
1819 if (TNY_IS_FOLDER (parent)) {
1820 /* Check folder rules */
1821 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1822 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1823 /* Set status failed and set an error */
1824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1825 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1826 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1827 _("mail_in_ui_folder_create_error"));
1831 if (!strcmp (name, " ") || strchr (name, '/')) {
1832 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1833 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1834 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1835 _("mail_in_ui_folder_create_error"));
1839 CreateFolderInfo *info;
1841 info = g_slice_new0 (CreateFolderInfo);
1842 info->mail_op = g_object_ref (self);
1843 info->callback = callback;
1844 info->user_data = user_data;
1846 modest_mail_operation_notify_start (self);
1848 /* Create the folder */
1849 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1852 /* Call the user callback anyway */
1854 callback (self, parent, NULL, user_data);
1855 /* Notify about operation end */
1856 modest_mail_operation_notify_end (self);
1861 modest_mail_operation_remove_folder (ModestMailOperation *self,
1863 gboolean remove_to_trash)
1865 ModestMailOperationPrivate *priv;
1866 ModestTnyFolderRules rules;
1868 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1869 g_return_if_fail (TNY_IS_FOLDER (folder));
1871 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1873 /* Check folder rules */
1874 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1875 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1876 /* Set status failed and set an error */
1877 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1878 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1879 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1880 _("mail_in_ui_folder_delete_error"));
1884 /* Get the account */
1885 priv->account = modest_tny_folder_get_account (folder);
1886 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1888 /* Delete folder or move to trash */
1889 if (remove_to_trash) {
1890 TnyFolder *trash_folder = NULL;
1891 trash_folder = modest_tny_account_get_special_folder (priv->account,
1892 TNY_FOLDER_TYPE_TRASH);
1893 /* TODO: error_handling */
1895 modest_mail_operation_notify_start (self);
1896 modest_mail_operation_xfer_folder (self, folder,
1897 TNY_FOLDER_STORE (trash_folder),
1899 g_object_unref (trash_folder);
1901 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1904 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1906 modest_mail_operation_notify_start (self);
1907 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1908 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1911 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1913 g_object_unref (parent);
1915 g_warning ("%s: could not get parent folder", __FUNCTION__);
1919 /* Notify about operation end */
1920 modest_mail_operation_notify_end (self);
1924 transfer_folder_status_cb (GObject *obj,
1928 ModestMailOperation *self;
1929 ModestMailOperationPrivate *priv;
1930 ModestMailOperationState *state;
1931 XFerFolderAsyncHelper *helper;
1933 g_return_if_fail (status != NULL);
1935 /* Show only the status information we want */
1936 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1939 helper = (XFerFolderAsyncHelper *) user_data;
1940 g_return_if_fail (helper != NULL);
1942 self = helper->mail_op;
1943 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1945 priv->done = status->position;
1946 priv->total = status->of_total;
1948 state = modest_mail_operation_clone_state (self);
1950 /* This is not a GDK lock because we are a Tinymail callback
1951 * which is already GDK locked by Tinymail */
1953 /* no gdk_threads_enter (), CHECKED */
1955 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1957 /* no gdk_threads_leave (), CHECKED */
1959 g_slice_free (ModestMailOperationState, state);
1964 transfer_folder_cb (TnyFolder *folder,
1966 TnyFolderStore *into,
1967 TnyFolder *new_folder,
1971 XFerFolderAsyncHelper *helper;
1972 ModestMailOperation *self = NULL;
1973 ModestMailOperationPrivate *priv = NULL;
1975 helper = (XFerFolderAsyncHelper *) user_data;
1976 g_return_if_fail (helper != NULL);
1978 self = helper->mail_op;
1979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1982 priv->error = g_error_copy (err);
1984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1985 } else if (cancelled) {
1986 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1987 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1988 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1989 _("Transference of %s was cancelled."),
1990 tny_folder_get_name (folder));
1993 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1996 /* Notify about operation end */
1997 modest_mail_operation_notify_end (self);
1999 /* If user defined callback function was defined, call it */
2000 if (helper->user_callback) {
2002 /* This is not a GDK lock because we are a Tinymail callback
2003 * which is already GDK locked by Tinymail */
2005 /* no gdk_threads_enter (), CHECKED */
2006 helper->user_callback (self, new_folder, helper->user_data);
2007 /* no gdk_threads_leave () , CHECKED */
2011 g_object_unref (helper->mail_op);
2012 g_slice_free (XFerFolderAsyncHelper, helper);
2017 * This function checks if the new name is a valid name for our local
2018 * folders account. The new name could not be the same than then name
2019 * of any of the mandatory local folders
2021 * We can not rely on tinymail because tinymail does not check the
2022 * name of the virtual folders that the account could have in the case
2023 * that we're doing a rename (because it directly calls Camel which
2024 * knows nothing about our virtual folders).
2026 * In the case of an actual copy/move (i.e. move/copy a folder between
2027 * accounts) tinymail uses the tny_folder_store_create_account which
2028 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2029 * checks the new name of the folder, so this call in that case
2030 * wouldn't be needed. *But* NOTE that if tinymail changes its
2031 * implementation (if folder transfers within the same account is no
2032 * longer implemented as a rename) this call will allow Modest to work
2035 * If the new name is not valid, this function will set the status to
2036 * failed and will set also an error in the mail operation
2039 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2040 TnyFolderStore *into,
2041 const gchar *new_name)
2043 if (TNY_IS_ACCOUNT (into) &&
2044 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2045 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2047 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2048 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2049 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2050 _CS("ckdg_ib_folder_already_exists"));
2057 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2059 TnyFolderStore *parent,
2060 gboolean delete_original,
2061 XferFolderAsyncUserCallback user_callback,
2064 ModestMailOperationPrivate *priv = NULL;
2065 ModestTnyFolderRules parent_rules = 0, rules;
2066 XFerFolderAsyncHelper *helper = NULL;
2067 const gchar *folder_name = NULL;
2068 const gchar *error_msg;
2070 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2071 g_return_if_fail (TNY_IS_FOLDER (folder));
2072 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2074 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2075 folder_name = tny_folder_get_name (folder);
2077 /* Set the error msg */
2078 error_msg = _("mail_in_ui_folder_move_target_error");
2080 /* Get account and set it into mail_operation */
2081 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2082 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2083 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2085 /* Get folder rules */
2086 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2087 if (TNY_IS_FOLDER (parent))
2088 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2090 /* Apply operation constraints */
2091 if ((gpointer) parent == (gpointer) folder ||
2092 (!TNY_IS_FOLDER_STORE (parent)) ||
2093 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2096 } else if (TNY_IS_FOLDER (parent) &&
2097 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2101 } else if (TNY_IS_FOLDER (parent) &&
2102 TNY_IS_FOLDER_STORE (folder) &&
2103 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2104 TNY_FOLDER_STORE (folder))) {
2105 /* Do not move a parent into a child */
2107 } else if (TNY_IS_FOLDER_STORE (parent) &&
2108 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2109 /* Check that the new folder name is not used by any
2112 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2113 /* Check that the new folder name is not used by any
2114 special local folder */
2117 /* Create the helper */
2118 helper = g_slice_new0 (XFerFolderAsyncHelper);
2119 helper->mail_op = g_object_ref (self);
2120 helper->user_callback = user_callback;
2121 helper->user_data = user_data;
2123 /* Move/Copy folder */
2124 modest_mail_operation_notify_start (self);
2125 tny_folder_copy_async (folder,
2127 tny_folder_get_name (folder),
2130 transfer_folder_status_cb,
2136 /* Set status failed and set an error */
2137 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2138 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2139 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2142 /* Call the user callback if exists */
2144 user_callback (self, NULL, user_data);
2146 /* Notify the queue */
2147 modest_mail_operation_notify_end (self);
2151 modest_mail_operation_rename_folder (ModestMailOperation *self,
2154 XferFolderAsyncUserCallback user_callback,
2157 ModestMailOperationPrivate *priv;
2158 ModestTnyFolderRules rules;
2159 XFerFolderAsyncHelper *helper;
2161 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2162 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2163 g_return_if_fail (name);
2165 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2167 /* Get account and set it into mail_operation */
2168 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2169 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2171 /* Check folder rules */
2172 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2173 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2175 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2178 TnyFolderStore *into;
2180 into = tny_folder_get_folder_store (folder);
2182 /* Check that the new folder name is not used by any
2183 special local folder */
2184 if (new_name_valid_if_local_account (priv, into, name)) {
2185 /* Create the helper */
2186 helper = g_slice_new0 (XFerFolderAsyncHelper);
2187 helper->mail_op = g_object_ref(self);
2188 helper->user_callback = user_callback;
2189 helper->user_data = user_data;
2191 /* Rename. Camel handles folder subscription/unsubscription */
2192 modest_mail_operation_notify_start (self);
2193 tny_folder_copy_async (folder, into, name, TRUE,
2195 transfer_folder_status_cb,
2197 g_object_unref (into);
2199 g_object_unref (into);
2206 /* Set status failed and set an error */
2207 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2208 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2209 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2210 _("FIXME: unable to rename"));
2213 user_callback (self, NULL, user_data);
2215 /* Notify about operation end */
2216 modest_mail_operation_notify_end (self);
2219 /* ******************************************************************* */
2220 /* ************************** MSG ACTIONS ************************* */
2221 /* ******************************************************************* */
2224 modest_mail_operation_get_msg (ModestMailOperation *self,
2226 gboolean progress_feedback,
2227 GetMsgAsyncUserCallback user_callback,
2230 GetMsgInfo *helper = NULL;
2232 ModestMailOperationPrivate *priv;
2234 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2235 g_return_if_fail (TNY_IS_HEADER (header));
2237 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2238 folder = tny_header_get_folder (header);
2240 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2244 /* Get account and set it into mail_operation */
2245 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2247 /* Check for cached messages */
2248 if (progress_feedback) {
2249 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2250 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2252 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2254 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2257 /* Create the helper */
2258 helper = g_slice_new0 (GetMsgInfo);
2259 helper->header = g_object_ref (header);
2260 helper->mail_op = g_object_ref (self);
2261 helper->user_callback = user_callback;
2262 helper->user_data = user_data;
2263 helper->destroy_notify = NULL;
2264 helper->last_total_bytes = 0;
2265 helper->sum_total_bytes = 0;
2266 helper->total_bytes = tny_header_get_message_size (header);
2267 helper->more_msgs = NULL;
2269 modest_mail_operation_notify_start (self);
2271 /* notify about the start of the operation */
2272 ModestMailOperationState *state;
2273 state = modest_mail_operation_clone_state (self);
2276 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2278 g_slice_free (ModestMailOperationState, state);
2280 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2282 g_object_unref (G_OBJECT (folder));
2286 get_msg_status_cb (GObject *obj,
2290 GetMsgInfo *helper = NULL;
2292 g_return_if_fail (status != NULL);
2294 /* Show only the status information we want */
2295 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2298 helper = (GetMsgInfo *) user_data;
2299 g_return_if_fail (helper != NULL);
2301 /* Notify progress */
2302 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2303 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2307 get_msg_async_cb (TnyFolder *folder,
2313 GetMsgInfo *info = NULL;
2314 ModestMailOperationPrivate *priv = NULL;
2317 info = (GetMsgInfo *) user_data;
2319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2322 if (info->more_msgs) {
2323 tny_iterator_next (info->more_msgs);
2324 finished = (tny_iterator_is_done (info->more_msgs));
2326 finished = (priv->done == priv->total) ? TRUE : FALSE;
2329 /* If canceled by the user, ignore the error given by Tinymail */
2333 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2335 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2337 priv->error = g_error_copy ((const GError *) err);
2338 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2341 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2342 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2345 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2346 /* Set the success status before calling the user callback */
2347 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2351 /* Call the user callback */
2352 if (info->user_callback)
2353 info->user_callback (info->mail_op, info->header, canceled,
2354 msg, err, info->user_data);
2356 /* Notify about operation end if this is the last callback */
2358 /* Free user data */
2359 if (info->destroy_notify)
2360 info->destroy_notify (info->user_data);
2362 /* Notify about operation end */
2363 modest_mail_operation_notify_end (info->mail_op);
2366 if (info->more_msgs)
2367 g_object_unref (info->more_msgs);
2368 g_object_unref (info->header);
2369 g_object_unref (info->mail_op);
2370 g_slice_free (GetMsgInfo, info);
2371 } else if (info->more_msgs) {
2372 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2373 TnyFolder *folder = tny_header_get_folder (header);
2375 g_object_unref (info->header);
2376 info->header = g_object_ref (header);
2378 /* Retrieve the next message */
2379 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2381 g_object_unref (header);
2382 g_object_unref (folder);
2384 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2389 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2390 TnyList *header_list,
2391 GetMsgAsyncUserCallback user_callback,
2393 GDestroyNotify notify)
2395 ModestMailOperationPrivate *priv = NULL;
2397 TnyIterator *iter = NULL;
2398 gboolean has_uncached_messages;
2400 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2402 /* Init mail operation */
2403 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2404 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2406 priv->total = tny_list_get_length(header_list);
2408 /* Check uncached messages */
2409 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2410 !has_uncached_messages && !tny_iterator_is_done (iter);
2411 tny_iterator_next (iter)) {
2414 header = (TnyHeader *) tny_iterator_get_current (iter);
2415 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2416 has_uncached_messages = TRUE;
2417 g_object_unref (header);
2419 g_object_unref (iter);
2420 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2422 /* Get account and set it into mail_operation */
2423 if (tny_list_get_length (header_list) >= 1) {
2424 TnyIterator *iterator = tny_list_create_iterator (header_list);
2425 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2427 TnyFolder *folder = tny_header_get_folder (header);
2429 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2430 g_object_unref (folder);
2432 g_object_unref (header);
2434 g_object_unref (iterator);
2437 msg_list_size = compute_message_list_size (header_list);
2439 modest_mail_operation_notify_start (self);
2440 iter = tny_list_create_iterator (header_list);
2441 if (!tny_iterator_is_done (iter)) {
2442 /* notify about the start of the operation */
2443 ModestMailOperationState *state;
2444 state = modest_mail_operation_clone_state (self);
2447 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2450 GetMsgInfo *msg_info = NULL;
2451 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2452 TnyFolder *folder = tny_header_get_folder (header);
2454 /* Create the message info */
2455 msg_info = g_slice_new0 (GetMsgInfo);
2456 msg_info->mail_op = g_object_ref (self);
2457 msg_info->header = g_object_ref (header);
2458 msg_info->more_msgs = g_object_ref (iter);
2459 msg_info->user_callback = user_callback;
2460 msg_info->user_data = user_data;
2461 msg_info->destroy_notify = notify;
2462 msg_info->last_total_bytes = 0;
2463 msg_info->sum_total_bytes = 0;
2464 msg_info->total_bytes = msg_list_size;
2466 /* The callback will call it per each header */
2467 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2469 /* Free and go on */
2470 g_object_unref (header);
2471 g_object_unref (folder);
2472 g_slice_free (ModestMailOperationState, state);
2474 g_object_unref (iter);
2479 remove_msgs_async_cb (TnyFolder *folder,
2484 gboolean expunge, leave_on_server;
2485 const gchar *account_name;
2487 TnyAccount *account;
2488 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2489 ModestMailOperation *self;
2490 ModestMailOperationPrivate *priv;
2492 self = (ModestMailOperation *) user_data;
2493 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2495 if (canceled || err) {
2496 /* If canceled by the user, ignore the error given by Tinymail */
2498 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2500 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2501 priv->error = g_error_copy ((const GError *) err);
2502 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2505 modest_mail_operation_notify_end (self);
2506 g_object_unref (self);
2510 account = tny_folder_get_account (folder);
2511 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2513 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2515 proto = tny_account_get_proto (account);
2516 g_object_unref (account);
2519 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2521 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2522 modest_tny_folder_is_remote_folder (folder) == FALSE)
2528 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2533 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2535 gboolean remove_to_trash /*ignored*/)
2537 TnyFolder *folder = NULL;
2538 ModestMailOperationPrivate *priv;
2539 TnyIterator *iter = NULL;
2540 TnyHeader *header = NULL;
2541 TnyList *remove_headers = NULL;
2542 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2544 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2545 g_return_if_fail (TNY_IS_LIST (headers));
2547 if (remove_to_trash)
2548 g_warning ("remove to trash is not implemented");
2550 if (tny_list_get_length(headers) == 0) {
2551 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2552 goto cleanup; /* nothing to do */
2555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2556 remove_headers = g_object_ref(headers);
2558 /* Get folder from first header and sync it */
2559 iter = tny_list_create_iterator (headers);
2560 header = TNY_HEADER (tny_iterator_get_current (iter));
2562 folder = tny_header_get_folder (header);
2563 if (!TNY_IS_FOLDER(folder)) {
2564 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2568 /* Don't remove messages that are being sent */
2569 if (modest_tny_folder_is_local_folder (folder)) {
2570 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2572 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2573 TnyTransportAccount *traccount = NULL;
2574 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2575 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2577 ModestTnySendQueueStatus status;
2578 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2579 TnyIterator *iter = tny_list_create_iterator(headers);
2580 g_object_unref(remove_headers);
2581 remove_headers = TNY_LIST(tny_simple_list_new());
2582 while (!tny_iterator_is_done(iter)) {
2584 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2585 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2586 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2587 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2588 tny_list_append(remove_headers, G_OBJECT(hdr));
2590 g_object_unref(hdr);
2592 tny_iterator_next(iter);
2594 g_object_unref(iter);
2595 g_object_unref(traccount);
2599 /* Get account and set it into mail_operation */
2600 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2601 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2602 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2604 /* remove message from folder */
2605 modest_mail_operation_notify_start (self);
2606 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2607 NULL, g_object_ref (self));
2611 g_object_unref (remove_headers);
2613 g_object_unref (header);
2615 g_object_unref (iter);
2617 g_object_unref (folder);
2621 notify_progress_of_multiple_messages (ModestMailOperation *self,
2623 gint *last_total_bytes,
2624 gint *sum_total_bytes,
2626 gboolean increment_done)
2628 ModestMailOperationPrivate *priv;
2629 ModestMailOperationState *state;
2630 gboolean is_num_bytes = FALSE;
2632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2634 /* We know that tinymail sends us information about
2635 * transferred bytes with this particular message
2637 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2638 * I just added the 'if' so we don't get runtime warning)
2640 if (status->message)
2641 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2643 state = modest_mail_operation_clone_state (self);
2644 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2645 /* We know that we're in a different message when the
2646 total number of bytes to transfer is different. Of
2647 course it could fail if we're transferring messages
2648 of the same size, but this is a workarround */
2649 if (status->of_total != *last_total_bytes) {
2650 /* We need to increment the done when there is
2651 no information about each individual
2652 message, we need to do this in message
2653 transfers, and we don't do it for getting
2657 *sum_total_bytes += *last_total_bytes;
2658 *last_total_bytes = status->of_total;
2660 state->bytes_done += status->position + *sum_total_bytes;
2661 state->bytes_total = total_bytes;
2663 /* Notify the status change. Only notify about changes
2664 referred to bytes */
2665 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2669 g_slice_free (ModestMailOperationState, state);
2673 transfer_msgs_status_cb (GObject *obj,
2677 XFerMsgsAsyncHelper *helper;
2679 g_return_if_fail (status != NULL);
2681 /* Show only the status information we want */
2682 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2685 helper = (XFerMsgsAsyncHelper *) user_data;
2686 g_return_if_fail (helper != NULL);
2688 /* Notify progress */
2689 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2690 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2695 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2697 XFerMsgsAsyncHelper *helper;
2698 ModestMailOperation *self;
2699 ModestMailOperationPrivate *priv;
2700 gboolean finished = TRUE;
2702 helper = (XFerMsgsAsyncHelper *) user_data;
2703 self = helper->mail_op;
2705 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2708 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2710 priv->error = g_error_copy (err);
2712 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2713 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2714 if (helper->more_msgs) {
2715 /* We'll transfer the next message in the list */
2716 tny_iterator_next (helper->more_msgs);
2717 if (!tny_iterator_is_done (helper->more_msgs)) {
2718 GObject *next_header;
2719 g_object_unref (helper->headers);
2720 helper->headers = tny_simple_list_new ();
2721 next_header = tny_iterator_get_current (helper->more_msgs);
2722 tny_list_append (helper->headers, next_header);
2723 g_object_unref (next_header);
2729 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2735 /* Update folder counts */
2736 tny_folder_poke_status (folder);
2737 tny_folder_poke_status (helper->dest_folder);
2739 /* Notify about operation end */
2740 modest_mail_operation_notify_end (self);
2742 /* If user defined callback function was defined, call it */
2743 if (helper->user_callback) {
2744 /* This is not a GDK lock because we are a Tinymail callback and
2745 * Tinymail already acquires the Gdk lock */
2747 /* no gdk_threads_enter (), CHECKED */
2748 helper->user_callback (self, helper->user_data);
2749 /* no gdk_threads_leave (), CHECKED */
2753 if (helper->more_msgs)
2754 g_object_unref (helper->more_msgs);
2755 if (helper->headers)
2756 g_object_unref (helper->headers);
2757 if (helper->dest_folder)
2758 g_object_unref (helper->dest_folder);
2759 if (helper->mail_op)
2760 g_object_unref (helper->mail_op);
2761 g_slice_free (XFerMsgsAsyncHelper, helper);
2763 /* Transfer more messages */
2764 tny_folder_transfer_msgs_async (folder,
2766 helper->dest_folder,
2769 transfer_msgs_status_cb,
2775 compute_message_list_size (TnyList *headers)
2780 iter = tny_list_create_iterator (headers);
2781 while (!tny_iterator_is_done (iter)) {
2782 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2783 size += tny_header_get_message_size (header);
2784 g_object_unref (header);
2785 tny_iterator_next (iter);
2787 g_object_unref (iter);
2793 compute_message_array_size (GPtrArray *headers)
2798 for (i = 0; i < headers->len; i++) {
2799 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2800 size += tny_header_get_message_size (header);
2808 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2811 gboolean delete_original,
2812 XferMsgsAsyncUserCallback user_callback,
2815 ModestMailOperationPrivate *priv = NULL;
2816 TnyIterator *iter = NULL;
2817 TnyFolder *src_folder = NULL;
2818 XFerMsgsAsyncHelper *helper = NULL;
2819 TnyHeader *header = NULL;
2820 ModestTnyFolderRules rules = 0;
2821 TnyAccount *dst_account = NULL;
2822 gboolean leave_on_server;
2824 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2825 g_return_if_fail (headers && TNY_IS_LIST (headers));
2826 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2829 priv->total = tny_list_get_length (headers);
2831 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2832 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2834 /* Apply folder rules */
2835 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2836 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2837 /* Set status failed and set an error */
2838 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2839 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2840 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2841 _CS("ckct_ib_unable_to_paste_here"));
2842 /* Notify the queue */
2843 modest_mail_operation_notify_end (self);
2847 /* Get source folder */
2848 iter = tny_list_create_iterator (headers);
2849 header = TNY_HEADER (tny_iterator_get_current (iter));
2851 src_folder = tny_header_get_folder (header);
2852 g_object_unref (header);
2854 g_object_unref (iter);
2856 if (src_folder == NULL) {
2857 /* Notify the queue */
2858 modest_mail_operation_notify_end (self);
2860 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2865 /* Check folder source and destination */
2866 if (src_folder == folder) {
2867 /* Set status failed and set an error */
2868 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2869 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2870 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2871 _("mail_in_ui_folder_copy_target_error"));
2873 /* Notify the queue */
2874 modest_mail_operation_notify_end (self);
2877 g_object_unref (src_folder);
2881 /* Create the helper */
2882 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2883 helper->mail_op = g_object_ref(self);
2884 helper->dest_folder = g_object_ref(folder);
2885 helper->user_callback = user_callback;
2886 helper->user_data = user_data;
2887 helper->last_total_bytes = 0;
2888 helper->sum_total_bytes = 0;
2889 helper->total_bytes = compute_message_list_size (headers);
2891 /* Get account and set it into mail_operation */
2892 priv->account = modest_tny_folder_get_account (src_folder);
2893 dst_account = modest_tny_folder_get_account (folder);
2895 if (priv->account == dst_account) {
2896 /* Transfer all messages at once using the fast
2897 * method. Note that depending on the server this
2898 * might not be that fast, and might not be
2899 * user-cancellable either */
2900 helper->headers = g_object_ref (headers);
2901 helper->more_msgs = NULL;
2903 /* Transfer messages one by one so the user can cancel
2906 helper->headers = tny_simple_list_new ();
2907 helper->more_msgs = tny_list_create_iterator (headers);
2908 hdr = tny_iterator_get_current (helper->more_msgs);
2909 tny_list_append (helper->headers, hdr);
2910 g_object_unref (hdr);
2913 /* If leave_on_server is set to TRUE then don't use
2914 delete_original, we always pass FALSE. This is because
2915 otherwise tinymail will try to sync the source folder and
2916 this could cause an error if we're offline while
2917 transferring an already downloaded message from a POP
2919 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2920 MODEST_PROTOCOL_STORE_POP) {
2921 const gchar *account_name;
2923 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2924 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2927 leave_on_server = FALSE;
2930 /* Do not delete messages if leave on server is TRUE */
2931 helper->delete = (leave_on_server) ? FALSE : delete_original;
2933 modest_mail_operation_notify_start (self);
2934 tny_folder_transfer_msgs_async (src_folder,
2939 transfer_msgs_status_cb,
2941 g_object_unref (src_folder);
2942 g_object_unref (dst_account);
2947 on_refresh_folder (TnyFolder *folder,
2952 RefreshAsyncHelper *helper = NULL;
2953 ModestMailOperation *self = NULL;
2954 ModestMailOperationPrivate *priv = NULL;
2956 helper = (RefreshAsyncHelper *) user_data;
2957 self = helper->mail_op;
2958 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2960 g_return_if_fail(priv!=NULL);
2963 priv->error = g_error_copy (error);
2964 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2969 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2970 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2971 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2972 _("Error trying to refresh the contents of %s"),
2973 tny_folder_get_name (folder));
2977 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2980 /* Call user defined callback, if it exists */
2981 if (helper->user_callback) {
2983 /* This is not a GDK lock because we are a Tinymail callback and
2984 * Tinymail already acquires the Gdk lock */
2985 helper->user_callback (self, folder, helper->user_data);
2989 g_slice_free (RefreshAsyncHelper, helper);
2991 /* Notify about operation end */
2992 modest_mail_operation_notify_end (self);
2993 g_object_unref(self);
2997 on_refresh_folder_status_update (GObject *obj,
3001 RefreshAsyncHelper *helper = NULL;
3002 ModestMailOperation *self = NULL;
3003 ModestMailOperationPrivate *priv = NULL;
3004 ModestMailOperationState *state;
3006 g_return_if_fail (user_data != NULL);
3007 g_return_if_fail (status != NULL);
3009 /* Show only the status information we want */
3010 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3013 helper = (RefreshAsyncHelper *) user_data;
3014 self = helper->mail_op;
3015 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3017 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3019 priv->done = status->position;
3020 priv->total = status->of_total;
3022 state = modest_mail_operation_clone_state (self);
3024 /* This is not a GDK lock because we are a Tinymail callback and
3025 * Tinymail already acquires the Gdk lock */
3026 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3028 g_slice_free (ModestMailOperationState, state);
3032 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3034 RefreshAsyncUserCallback user_callback,
3037 ModestMailOperationPrivate *priv = NULL;
3038 RefreshAsyncHelper *helper = NULL;
3040 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3042 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3044 /* Get account and set it into mail_operation */
3045 priv->account = modest_tny_folder_get_account (folder);
3046 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3048 /* Create the helper */
3049 helper = g_slice_new0 (RefreshAsyncHelper);
3050 helper->mail_op = g_object_ref(self);
3051 helper->user_callback = user_callback;
3052 helper->user_data = user_data;
3054 modest_mail_operation_notify_start (self);
3056 /* notify that the operation was started */
3057 ModestMailOperationState *state;
3058 state = modest_mail_operation_clone_state (self);
3061 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3064 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3066 tny_folder_refresh_async (folder,
3068 on_refresh_folder_status_update,
3073 run_queue_stop (ModestTnySendQueue *queue,
3074 ModestMailOperation *self)
3076 ModestMailOperationPrivate *priv;
3078 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3079 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3082 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3084 modest_mail_operation_notify_end (self);
3085 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3086 g_object_unref (self);
3089 modest_mail_operation_run_queue (ModestMailOperation *self,
3090 ModestTnySendQueue *queue)
3092 ModestMailOperationPrivate *priv;
3094 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3095 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3098 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3099 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3100 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3102 modest_mail_operation_notify_start (self);
3103 g_object_ref (self);
3104 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3108 sync_folder_finish_callback (TnyFolder *self,
3114 ModestMailOperation *mail_op;
3115 ModestMailOperationPrivate *priv;
3117 mail_op = (ModestMailOperation *) user_data;
3118 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3120 /* If canceled by the user, ignore the error given by Tinymail */
3122 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3124 /* If the operation was a sync then the status is
3125 failed, but if it's part of another operation then
3126 just set it as finished with errors */
3127 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3128 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3130 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3131 priv->error = g_error_copy ((const GError *) err);
3132 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3134 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3137 modest_mail_operation_notify_end (mail_op);
3138 g_object_unref (mail_op);
3142 modest_mail_operation_sync_folder (ModestMailOperation *self,
3143 TnyFolder *folder, gboolean expunge)
3145 ModestMailOperationPrivate *priv;
3147 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3148 g_return_if_fail (TNY_IS_FOLDER (folder));
3149 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3151 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3152 priv->account = modest_tny_folder_get_account (folder);
3153 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3155 modest_mail_operation_notify_start (self);
3156 g_object_ref (self);
3157 tny_folder_sync_async (folder, expunge,
3158 (TnyFolderCallback) sync_folder_finish_callback,
3163 modest_mail_operation_notify_start (ModestMailOperation *self)
3165 ModestMailOperationPrivate *priv = NULL;
3167 g_return_if_fail (self);
3169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3171 /* Ensure that all the fields are filled correctly */
3172 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3174 /* Notify the observers about the mail operation. We do not
3175 wrapp this emission because we assume that this function is
3176 always called from within the main lock */
3177 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3182 * It's used by the mail operation queue to notify the observers
3183 * attached to that signal that the operation finished. We need to use
3184 * that because tinymail does not give us the progress of a given
3185 * operation when it finishes (it directly calls the operation
3189 modest_mail_operation_notify_end (ModestMailOperation *self)
3191 ModestMailOperationPrivate *priv = NULL;
3193 g_return_if_fail (self);
3195 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3197 /* Notify the observers about the mail operation end. We do
3198 not wrapp this emission because we assume that this
3199 function is always called from within the main lock */
3200 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3202 /* Remove the error user data */
3203 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3204 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3208 modest_mail_operation_get_account (ModestMailOperation *self)
3210 ModestMailOperationPrivate *priv = NULL;
3212 g_return_val_if_fail (self, NULL);
3214 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3216 return (priv->account) ? g_object_ref (priv->account) : NULL;
3220 modest_mail_operation_noop (ModestMailOperation *self)
3222 ModestMailOperationPrivate *priv = NULL;
3224 g_return_if_fail (self);
3226 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3227 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3228 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3232 /* This mail operation does nothing actually */
3233 modest_mail_operation_notify_start (self);
3234 modest_mail_operation_notify_end (self);
3239 modest_mail_operation_to_string (ModestMailOperation *self)
3241 const gchar *type, *status, *account_id;
3242 ModestMailOperationPrivate *priv = NULL;
3244 g_return_val_if_fail (self, NULL);
3246 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3248 /* new operations don't have anything interesting */
3249 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3250 return g_strdup_printf ("%p <new operation>", self);
3252 switch (priv->op_type) {
3253 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3254 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3255 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3256 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3257 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3258 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3259 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3260 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3261 default: type = "UNEXPECTED"; break;
3264 switch (priv->status) {
3265 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3266 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3267 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3268 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3269 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3270 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3271 default: status= "UNEXPECTED"; break;
3274 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3276 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3277 priv->done, priv->total,
3278 priv->error && priv->error->message ? priv->error->message : "");