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));
509 /* Cancel the sending of the following next messages */
510 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
517 modest_mail_operation_get_task_done (ModestMailOperation *self)
519 ModestMailOperationPrivate *priv;
521 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
529 modest_mail_operation_get_task_total (ModestMailOperation *self)
531 ModestMailOperationPrivate *priv;
533 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
541 modest_mail_operation_is_finished (ModestMailOperation *self)
543 ModestMailOperationPrivate *priv;
544 gboolean retval = FALSE;
546 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
551 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
552 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
553 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
554 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
564 * Creates an image of the current state of a mail operation, the
565 * caller must free it
567 static ModestMailOperationState *
568 modest_mail_operation_clone_state (ModestMailOperation *self)
570 ModestMailOperationState *state;
571 ModestMailOperationPrivate *priv;
573 /* FIXME: this should be fixed properly
575 * in some cases, priv was NULL, so checking here to
578 g_return_val_if_fail (self, NULL);
579 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
580 g_return_val_if_fail (priv, NULL);
585 state = g_slice_new (ModestMailOperationState);
587 state->status = priv->status;
588 state->op_type = priv->op_type;
589 state->done = priv->done;
590 state->total = priv->total;
591 state->finished = modest_mail_operation_is_finished (self);
592 state->bytes_done = 0;
593 state->bytes_total = 0;
598 /* ******************************************************************* */
599 /* ************************** SEND ACTIONS ************************* */
600 /* ******************************************************************* */
603 modest_mail_operation_send_mail (ModestMailOperation *self,
604 TnyTransportAccount *transport_account,
607 TnySendQueue *send_queue = NULL;
608 ModestMailOperationPrivate *priv;
610 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
611 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
612 g_return_if_fail (msg && TNY_IS_MSG (msg));
614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
616 /* Get account and set it into mail_operation */
617 priv->account = g_object_ref (transport_account);
618 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
622 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
623 if (!TNY_IS_SEND_QUEUE(send_queue)) {
624 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
625 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
626 "modest: could not find send queue for account\n");
627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
628 modest_mail_operation_notify_end (self);
631 /* Add the msg to the queue */
632 modest_mail_operation_notify_start (self);
634 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
635 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE);
637 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
638 modest_mail_operation_notify_end (self);
645 idle_create_msg_cb (gpointer idle_data)
647 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
649 /* This is a GDK lock because we are an idle callback and
650 * info->callback can contain Gtk+ code */
652 gdk_threads_enter (); /* CHECKED */
653 info->callback (info->mail_op, info->msg, info->userdata);
655 g_object_unref (info->mail_op);
657 g_object_unref (info->msg);
658 g_slice_free (CreateMsgIdleInfo, info);
659 gdk_threads_leave (); /* CHECKED */
665 create_msg_thread (gpointer thread_data)
667 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
668 TnyMsg *new_msg = NULL;
669 ModestMailOperationPrivate *priv;
671 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
672 if (info->html_body == NULL) {
673 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
674 info->bcc, info->subject, info->plain_body,
675 info->attachments_list);
677 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
678 info->bcc, info->subject, info->html_body,
679 info->plain_body, info->attachments_list,
686 /* Set priority flags in message */
687 header = tny_msg_get_header (new_msg);
688 tny_header_set_flag (header, info->priority_flags);
690 /* Set attachment flags in message */
691 if (info->attachments_list != NULL)
692 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
694 g_object_unref (G_OBJECT(header));
696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
698 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
699 "modest: failed to create a new msg\n");
707 g_free (info->plain_body);
708 g_free (info->html_body);
709 g_free (info->subject);
710 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
711 g_list_free (info->attachments_list);
712 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
713 g_list_free (info->images_list);
715 if (info->callback) {
716 CreateMsgIdleInfo *idle_info;
717 idle_info = g_slice_new0 (CreateMsgIdleInfo);
718 idle_info->mail_op = g_object_ref (info->mail_op);
719 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
720 idle_info->callback = info->callback;
721 idle_info->userdata = info->userdata;
722 g_idle_add (idle_create_msg_cb, idle_info);
724 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
727 g_object_unref (info->mail_op);
728 g_slice_free (CreateMsgInfo, info);
729 if (new_msg) g_object_unref(new_msg);
735 modest_mail_operation_create_msg (ModestMailOperation *self,
736 const gchar *from, const gchar *to,
737 const gchar *cc, const gchar *bcc,
738 const gchar *subject, const gchar *plain_body,
739 const gchar *html_body,
740 const GList *attachments_list,
741 const GList *images_list,
742 TnyHeaderFlags priority_flags,
743 ModestMailOperationCreateMsgCallback callback,
746 CreateMsgInfo *info = NULL;
748 info = g_slice_new0 (CreateMsgInfo);
749 info->mail_op = g_object_ref (self);
751 info->from = g_strdup (from);
752 info->to = g_strdup (to);
753 info->cc = g_strdup (cc);
754 info->bcc = g_strdup (bcc);
755 info->subject = g_strdup (subject);
756 info->plain_body = g_strdup (plain_body);
757 info->html_body = g_strdup (html_body);
758 info->attachments_list = g_list_copy ((GList *) attachments_list);
759 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
760 info->images_list = g_list_copy ((GList *) images_list);
761 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
762 info->priority_flags = priority_flags;
764 info->callback = callback;
765 info->userdata = userdata;
767 g_thread_create (create_msg_thread, info, FALSE, NULL);
772 TnyTransportAccount *transport_account;
777 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
781 ModestMailOperationPrivate *priv = NULL;
782 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
783 TnyFolder *draft_folder = NULL;
784 TnyFolder *outbox_folder = NULL;
785 TnyHeader *header = NULL;
791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
794 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
795 modest_mail_operation_notify_end (self);
799 /* Call mail operation */
800 modest_mail_operation_send_mail (self, info->transport_account, msg);
802 if (info->draft_msg != NULL) {
803 TnyList *tmp_headers = NULL;
804 TnyFolder *folder = NULL;
805 TnyFolder *src_folder = NULL;
806 TnyFolderType folder_type;
807 TnyTransportAccount *transport_account = NULL;
809 /* To remove the old mail from its source folder, we need to get the
810 * transport account of the original draft message (the transport account
811 * might have been changed by the user) */
812 header = tny_msg_get_header (info->draft_msg);
813 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
814 modest_runtime_get_account_store(), header);
815 if (transport_account == NULL)
816 transport_account = g_object_ref(info->transport_account);
817 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
818 TNY_FOLDER_TYPE_DRAFTS);
819 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
820 TNY_FOLDER_TYPE_OUTBOX);
821 g_object_unref(transport_account);
824 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
828 if (!outbox_folder) {
829 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
834 folder = tny_msg_get_folder (info->draft_msg);
835 if (folder == NULL) goto end;
836 folder_type = modest_tny_folder_guess_folder_type (folder);
838 if (folder_type == TNY_FOLDER_TYPE_INVALID)
839 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
841 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
842 src_folder = outbox_folder;
844 src_folder = draft_folder;
846 /* Note: This can fail (with a warning) if the message is not really already in a folder,
847 * because this function requires it to have a UID. */
848 tmp_headers = tny_simple_list_new ();
849 tny_list_append (tmp_headers, (GObject*) header);
850 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
851 g_object_unref (tmp_headers);
852 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
854 g_object_unref (folder);
859 g_object_unref (header);
861 g_object_unref (info->draft_msg);
863 g_object_unref (draft_folder);
865 g_object_unref (outbox_folder);
866 if (info->transport_account)
867 g_object_unref (info->transport_account);
868 g_slice_free (SendNewMailInfo, info);
872 modest_mail_operation_send_new_mail (ModestMailOperation *self,
873 TnyTransportAccount *transport_account,
875 const gchar *from, const gchar *to,
876 const gchar *cc, const gchar *bcc,
877 const gchar *subject, const gchar *plain_body,
878 const gchar *html_body,
879 const GList *attachments_list,
880 const GList *images_list,
881 TnyHeaderFlags priority_flags)
883 ModestMailOperationPrivate *priv = NULL;
884 SendNewMailInfo *info;
886 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
887 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
889 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
890 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
891 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
892 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
894 /* Check parametters */
896 /* Set status failed and set an error */
897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
898 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
899 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
900 _("Error trying to send a mail. You need to set at least one recipient"));
903 info = g_slice_new0 (SendNewMailInfo);
904 info->transport_account = transport_account;
905 if (transport_account)
906 g_object_ref (transport_account);
907 info->draft_msg = draft_msg;
909 g_object_ref (draft_msg);
912 modest_mail_operation_notify_start (self);
913 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
914 attachments_list, images_list, priority_flags,
915 modest_mail_operation_send_new_mail_cb, info);
921 TnyTransportAccount *transport_account;
923 SaveToDraftstCallback callback;
927 ModestMailOperation *mailop;
928 } SaveToDraftsAddMsgInfo;
931 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
936 ModestMailOperationPrivate *priv = NULL;
937 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
939 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
942 g_warning ("%s: priv->error != NULL", __FUNCTION__);
943 g_error_free(priv->error);
946 priv->error = (err == NULL) ? NULL : g_error_copy(err);
948 if ((!priv->error) && (info->draft_msg != NULL)) {
949 TnyHeader *header = tny_msg_get_header (info->draft_msg);
950 TnyFolder *src_folder = tny_header_get_folder (header);
952 /* Remove the old draft */
953 tny_folder_remove_msg (src_folder, header, NULL);
955 /* Synchronize to expunge and to update the msg counts */
956 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
957 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
959 g_object_unref (G_OBJECT(header));
960 g_object_unref (G_OBJECT(src_folder));
964 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
966 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
968 /* Call the user callback */
970 info->callback (info->mailop, info->msg, info->user_data);
972 if (info->transport_account)
973 g_object_unref (G_OBJECT(info->transport_account));
975 g_object_unref (G_OBJECT (info->draft_msg));
977 g_object_unref (G_OBJECT(info->drafts));
979 g_object_unref (G_OBJECT (info->msg));
981 modest_mail_operation_notify_end (info->mailop);
982 g_object_unref(info->mailop);
983 g_slice_free (SaveToDraftsAddMsgInfo, info);
988 TnyTransportAccount *transport_account;
990 SaveToDraftstCallback callback;
995 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
999 TnyFolder *drafts = NULL;
1000 ModestMailOperationPrivate *priv = NULL;
1001 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1003 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1006 if (!(priv->error)) {
1007 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1008 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1009 "modest: failed to create a new msg\n");
1012 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1013 TNY_FOLDER_TYPE_DRAFTS);
1014 if (!drafts && !(priv->error)) {
1015 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1016 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1017 "modest: failed to create a new msg\n");
1022 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1023 cb_info->transport_account = g_object_ref(info->transport_account);
1024 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1025 cb_info->callback = info->callback;
1026 cb_info->user_data = info->user_data;
1027 cb_info->drafts = g_object_ref(drafts);
1028 cb_info->msg = g_object_ref(msg);
1029 cb_info->mailop = g_object_ref(self);
1030 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1033 /* Call the user callback */
1034 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1036 info->callback (self, msg, info->user_data);
1037 modest_mail_operation_notify_end (self);
1041 g_object_unref (G_OBJECT(drafts));
1042 if (info->draft_msg)
1043 g_object_unref (G_OBJECT (info->draft_msg));
1044 if (info->transport_account)
1045 g_object_unref (G_OBJECT(info->transport_account));
1046 g_slice_free (SaveToDraftsInfo, info);
1050 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1051 TnyTransportAccount *transport_account,
1053 const gchar *from, const gchar *to,
1054 const gchar *cc, const gchar *bcc,
1055 const gchar *subject, const gchar *plain_body,
1056 const gchar *html_body,
1057 const GList *attachments_list,
1058 const GList *images_list,
1059 TnyHeaderFlags priority_flags,
1060 SaveToDraftstCallback callback,
1063 ModestMailOperationPrivate *priv = NULL;
1064 SaveToDraftsInfo *info = NULL;
1066 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1067 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1069 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1071 /* Get account and set it into mail_operation */
1072 priv->account = g_object_ref (transport_account);
1073 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1075 info = g_slice_new0 (SaveToDraftsInfo);
1076 info->transport_account = g_object_ref (transport_account);
1077 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1078 info->callback = callback;
1079 info->user_data = user_data;
1081 modest_mail_operation_notify_start (self);
1082 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1083 attachments_list, images_list, priority_flags,
1084 modest_mail_operation_save_to_drafts_cb, info);
1089 ModestMailOperation *mail_op;
1090 TnyMimePart *mime_part;
1092 GetMimePartSizeCallback callback;
1094 } GetMimePartSizeInfo;
1096 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1097 /* We use this folder observer to track the headers that have been
1098 * added to a folder */
1101 TnyList *new_headers;
1102 } InternalFolderObserver;
1105 GObjectClass parent;
1106 } InternalFolderObserverClass;
1108 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1110 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1111 internal_folder_observer,
1113 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1117 foreach_add_item (gpointer header, gpointer user_data)
1119 tny_list_prepend (TNY_LIST (user_data),
1120 g_object_ref (G_OBJECT (header)));
1123 /* This is the method that looks for new messages in a folder */
1125 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1127 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1129 TnyFolderChangeChanged changed;
1131 changed = tny_folder_change_get_changed (change);
1133 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1136 /* Get added headers */
1137 list = tny_simple_list_new ();
1138 tny_folder_change_get_added_headers (change, list);
1140 /* Add them to the folder observer */
1141 tny_list_foreach (list, foreach_add_item,
1142 derived->new_headers);
1144 g_object_unref (G_OBJECT (list));
1149 internal_folder_observer_init (InternalFolderObserver *self)
1151 self->new_headers = tny_simple_list_new ();
1154 internal_folder_observer_finalize (GObject *object)
1156 InternalFolderObserver *self;
1158 self = (InternalFolderObserver *) object;
1159 g_object_unref (self->new_headers);
1161 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1164 tny_folder_observer_init (TnyFolderObserverIface *iface)
1166 iface->update = internal_folder_observer_update;
1169 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1171 GObjectClass *object_class;
1173 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1174 object_class = (GObjectClass*) klass;
1175 object_class->finalize = internal_folder_observer_finalize;
1180 ModestMailOperation *mail_op;
1181 gchar *account_name;
1182 UpdateAccountCallback callback;
1187 TnyFolderObserver *inbox_observer;
1188 RetrieveAllCallback retrieve_all_cb;
1189 gboolean interactive;
1190 } UpdateAccountInfo;
1194 destroy_update_account_info (UpdateAccountInfo *info)
1196 g_free (info->account_name);
1197 g_object_unref (info->folders);
1198 g_object_unref (info->mail_op);
1199 g_slice_free (UpdateAccountInfo, info);
1203 update_account_get_msg_async_cb (TnyFolder *folder,
1209 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1211 /* Just delete the helper. Don't do anything with the new
1212 msg. There is also no need to check for errors */
1213 g_object_unref (msg_info->mail_op);
1214 g_object_unref (msg_info->header);
1215 g_slice_free (GetMsgInfo, msg_info);
1219 update_account_notify_user_and_free (UpdateAccountInfo *info,
1220 TnyList *new_headers)
1222 /* Set the account back to not busy */
1223 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1224 info->account_name, FALSE);
1228 info->callback (info->mail_op, new_headers, info->user_data);
1230 /* Mail operation end */
1231 modest_mail_operation_notify_end (info->mail_op);
1235 g_object_unref (new_headers);
1236 destroy_update_account_info (info);
1240 inbox_refreshed_cb (TnyFolder *inbox,
1245 UpdateAccountInfo *info;
1246 ModestMailOperationPrivate *priv;
1247 TnyIterator *new_headers_iter;
1248 GPtrArray *new_headers_array = NULL;
1249 gint max_size, retrieve_limit, i;
1250 ModestAccountMgr *mgr;
1251 ModestAccountRetrieveType retrieve_type;
1252 TnyList *new_headers = NULL;
1253 gboolean headers_only, ignore_limit;
1254 TnyTransportAccount *transport_account = NULL;
1256 info = (UpdateAccountInfo *) user_data;
1257 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1258 mgr = modest_runtime_get_account_mgr ();
1260 if (canceled || err) {
1261 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1263 priv->error = g_error_copy (err);
1265 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1266 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1268 /* Notify the user about the error and then exit */
1269 update_account_notify_user_and_free (info, NULL);
1274 /* Try to send anyway */
1278 /* Get the message max size */
1279 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1280 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1282 max_size = G_MAXINT;
1284 max_size = max_size * KB;
1286 /* Create the new headers array. We need it to sort the
1287 new headers by date */
1288 new_headers_array = g_ptr_array_new ();
1289 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1290 while (!tny_iterator_is_done (new_headers_iter)) {
1291 TnyHeader *header = NULL;
1293 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1294 /* Apply per-message size limits */
1295 if (tny_header_get_message_size (header) < max_size)
1296 g_ptr_array_add (new_headers_array, g_object_ref (header));
1298 g_object_unref (header);
1299 tny_iterator_next (new_headers_iter);
1301 g_object_unref (new_headers_iter);
1302 tny_folder_remove_observer (inbox, info->inbox_observer);
1303 g_object_unref (info->inbox_observer);
1304 info->inbox_observer = NULL;
1306 /* Update the last updated key, even if we don't have to get new headers */
1307 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1309 if (new_headers_array->len == 0)
1312 /* Get per-account message amount retrieval limit */
1313 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1314 if (retrieve_limit == 0)
1315 retrieve_limit = G_MAXINT;
1317 /* Get per-account retrieval type */
1318 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1319 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1322 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1324 /* Ask the users if they want to retrieve all the messages
1325 even though the limit was exceeded */
1326 ignore_limit = FALSE;
1327 if (new_headers_array->len > retrieve_limit) {
1328 /* Ask the user if a callback has been specified and
1329 if the mail operation has a source (this means that
1330 was invoked by the user and not automatically by a
1332 if (info->retrieve_all_cb && priv->source)
1333 ignore_limit = info->retrieve_all_cb (priv->source,
1334 new_headers_array->len,
1338 if (!headers_only) {
1340 const gint msg_list_size = compute_message_array_size (new_headers_array);
1344 priv->total = new_headers_array->len;
1346 priv->total = MIN (new_headers_array->len, retrieve_limit);
1347 while (msg_num < priv->total) {
1348 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1349 TnyFolder *folder = tny_header_get_folder (header);
1350 GetMsgInfo *msg_info;
1352 /* Create the message info */
1353 msg_info = g_slice_new0 (GetMsgInfo);
1354 msg_info->mail_op = g_object_ref (info->mail_op);
1355 msg_info->header = g_object_ref (header);
1356 msg_info->total_bytes = msg_list_size;
1358 /* Get message in an async way */
1359 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1360 get_msg_status_cb, msg_info);
1362 g_object_unref (folder);
1368 /* Copy the headers to a list and free the array */
1369 new_headers = tny_simple_list_new ();
1370 for (i=0; i < new_headers_array->len; i++) {
1371 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1372 tny_list_append (new_headers, G_OBJECT (header));
1374 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1375 g_ptr_array_free (new_headers_array, FALSE);
1378 /* Get the transport account */
1379 transport_account = (TnyTransportAccount *)
1380 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1381 info->account_name);
1383 if (transport_account) {
1384 ModestTnySendQueue *send_queue;
1388 send_queue = modest_runtime_get_send_queue (transport_account);
1389 g_object_unref (transport_account);
1391 /* Get outbox folder */
1392 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1393 if (outbox) { /* this could fail in some cases */
1394 num_messages = tny_folder_get_all_count (outbox);
1395 g_object_unref (outbox);
1397 g_warning ("%s: could not get outbox", __FUNCTION__);
1401 if (num_messages != 0) {
1402 /* Reenable suspended items */
1403 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1406 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1407 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1412 /* Check if the operation was a success */
1414 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1416 /* Call the user callback and free */
1417 update_account_notify_user_and_free (info, new_headers);
1421 recurse_folders_async_cb (TnyFolderStore *folder_store,
1427 UpdateAccountInfo *info;
1428 ModestMailOperationPrivate *priv;
1430 info = (UpdateAccountInfo *) user_data;
1431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1433 if (err || canceled) {
1434 /* If the error was previosly set by another callback
1435 don't set it again */
1437 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1439 priv->error = g_error_copy (err);
1441 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1442 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1446 /* We're not getting INBOX children if we don't want to poke all */
1447 TnyIterator *iter = tny_list_create_iterator (list);
1448 while (!tny_iterator_is_done (iter)) {
1449 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1451 /* Add to the list of all folders */
1452 tny_list_append (info->folders, (GObject *) folder);
1454 if (info->poke_all) {
1455 TnyList *folders = tny_simple_list_new ();
1456 /* Add pending call */
1457 info->pending_calls++;
1459 tny_folder_store_get_folders_async (folder, folders, NULL,
1460 recurse_folders_async_cb,
1462 g_object_unref (folders);
1465 g_object_unref (G_OBJECT (folder));
1467 tny_iterator_next (iter);
1469 g_object_unref (G_OBJECT (iter));
1472 /* Remove my own pending call */
1473 info->pending_calls--;
1475 /* This means that we have all the folders */
1476 if (info->pending_calls == 0) {
1477 TnyIterator *iter_all_folders;
1478 TnyFolder *inbox = NULL;
1480 /* If there was any error do not continue */
1482 update_account_notify_user_and_free (info, NULL);
1486 iter_all_folders = tny_list_create_iterator (info->folders);
1488 /* Do a poke status over all folders */
1489 while (!tny_iterator_is_done (iter_all_folders) &&
1490 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1491 TnyFolder *folder = NULL;
1493 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1495 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1496 /* Get a reference to the INBOX */
1497 inbox = g_object_ref (folder);
1499 /* Issue a poke status over the folder */
1501 tny_folder_poke_status (folder);
1504 /* Free and go to next */
1505 g_object_unref (folder);
1506 tny_iterator_next (iter_all_folders);
1508 g_object_unref (iter_all_folders);
1510 /* Refresh the INBOX */
1512 /* Refresh the folder. Our observer receives
1513 * the new emails during folder refreshes, so
1514 * we can use observer->new_headers
1516 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1517 tny_folder_add_observer (inbox, info->inbox_observer);
1519 /* Refresh the INBOX */
1520 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1521 g_object_unref (inbox);
1523 /* We could not perform the inbox refresh but
1524 we'll try to send mails anyway */
1525 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1531 modest_mail_operation_update_account (ModestMailOperation *self,
1532 const gchar *account_name,
1534 gboolean interactive,
1535 RetrieveAllCallback retrieve_all_cb,
1536 UpdateAccountCallback callback,
1539 UpdateAccountInfo *info = NULL;
1540 ModestMailOperationPrivate *priv = NULL;
1541 ModestTnyAccountStore *account_store = NULL;
1543 ModestMailOperationState *state;
1545 /* Init mail operation */
1546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1549 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1550 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1552 /* Get the store account */
1553 account_store = modest_runtime_get_account_store ();
1555 modest_tny_account_store_get_server_account (account_store,
1557 TNY_ACCOUNT_TYPE_STORE);
1559 /* The above function could return NULL */
1560 if (!priv->account) {
1561 /* Check if the operation was a success */
1562 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1563 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1567 /* Call the user callback */
1569 callback (self, NULL, user_data);
1571 /* Notify about operation end */
1572 modest_mail_operation_notify_end (self);
1577 /* We have once seen priv->account getting finalized during this code,
1578 * therefore adding a reference (bug #82296) */
1580 g_object_ref (priv->account);
1582 /* Create the helper object */
1583 info = g_slice_new0 (UpdateAccountInfo);
1584 info->pending_calls = 1;
1585 info->folders = tny_simple_list_new ();
1586 info->mail_op = g_object_ref (self);
1587 info->poke_all = poke_all;
1588 info->interactive = interactive;
1589 info->account_name = g_strdup (account_name);
1590 info->callback = callback;
1591 info->user_data = user_data;
1592 info->retrieve_all_cb = retrieve_all_cb;
1594 /* Set account busy */
1595 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1596 modest_mail_operation_notify_start (self);
1598 /* notify about the start of the operation */
1599 state = modest_mail_operation_clone_state (self);
1603 /* Start notifying progress */
1604 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1605 g_slice_free (ModestMailOperationState, state);
1607 /* Get all folders and continue in the callback */
1608 folders = tny_simple_list_new ();
1609 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1611 recurse_folders_async_cb,
1613 g_object_unref (folders);
1615 g_object_unref (priv->account);
1620 * Used to notify the queue from the main
1621 * loop. We call it inside an idle call to achieve that
1624 idle_notify_queue (gpointer data)
1626 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1628 gdk_threads_enter ();
1629 modest_mail_operation_notify_end (mail_op);
1630 gdk_threads_leave ();
1631 g_object_unref (mail_op);
1637 compare_headers_by_date (gconstpointer a,
1640 TnyHeader **header1, **header2;
1641 time_t sent1, sent2;
1643 header1 = (TnyHeader **) a;
1644 header2 = (TnyHeader **) b;
1646 sent1 = tny_header_get_date_sent (*header1);
1647 sent2 = tny_header_get_date_sent (*header2);
1649 /* We want the most recent ones (greater time_t) at the
1658 /* ******************************************************************* */
1659 /* ************************** STORE ACTIONS ************************* */
1660 /* ******************************************************************* */
1663 ModestMailOperation *mail_op;
1664 CreateFolderUserCallback callback;
1670 create_folder_cb (TnyFolderStore *parent_folder,
1672 TnyFolder *new_folder,
1676 ModestMailOperationPrivate *priv;
1677 CreateFolderInfo *info;
1679 info = (CreateFolderInfo *) user_data;
1680 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1682 if (canceled || err) {
1683 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1685 priv->error = g_error_copy (err);
1687 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1688 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1691 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1694 /* The user will unref the new_folder */
1696 info->callback (info->mail_op, parent_folder,
1697 new_folder, info->user_data);
1699 /* Notify about operation end */
1700 modest_mail_operation_notify_end (info->mail_op);
1703 g_object_unref (info->mail_op);
1704 g_slice_free (CreateFolderInfo, info);
1708 modest_mail_operation_create_folder (ModestMailOperation *self,
1709 TnyFolderStore *parent,
1711 CreateFolderUserCallback callback,
1714 ModestMailOperationPrivate *priv;
1716 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1717 g_return_if_fail (name);
1719 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1720 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1721 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1722 g_object_ref (parent) :
1723 modest_tny_folder_get_account (TNY_FOLDER (parent));
1725 /* Check for already existing folder */
1726 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1727 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1728 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1729 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1730 _CS("ckdg_ib_folder_already_exists"));
1734 if (TNY_IS_FOLDER (parent)) {
1735 /* Check folder rules */
1736 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1737 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1738 /* Set status failed and set an error */
1739 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1740 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1741 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1742 _("mail_in_ui_folder_create_error"));
1746 if (!strcmp (name, " ") || strchr (name, '/')) {
1747 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1748 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1749 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1750 _("mail_in_ui_folder_create_error"));
1754 CreateFolderInfo *info;
1756 info = g_slice_new0 (CreateFolderInfo);
1757 info->mail_op = g_object_ref (self);
1758 info->callback = callback;
1759 info->user_data = user_data;
1761 modest_mail_operation_notify_start (self);
1763 /* Create the folder */
1764 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1767 /* Call the user callback anyway */
1769 callback (self, parent, NULL, user_data);
1770 /* Notify about operation end */
1771 modest_mail_operation_notify_end (self);
1776 modest_mail_operation_remove_folder (ModestMailOperation *self,
1778 gboolean remove_to_trash)
1780 ModestMailOperationPrivate *priv;
1781 ModestTnyFolderRules rules;
1783 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1784 g_return_if_fail (TNY_IS_FOLDER (folder));
1786 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1788 /* Check folder rules */
1789 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1790 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1791 /* Set status failed and set an error */
1792 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1793 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1794 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1795 _("mail_in_ui_folder_delete_error"));
1799 /* Get the account */
1800 priv->account = modest_tny_folder_get_account (folder);
1801 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1803 /* Delete folder or move to trash */
1804 if (remove_to_trash) {
1805 TnyFolder *trash_folder = NULL;
1806 trash_folder = modest_tny_account_get_special_folder (priv->account,
1807 TNY_FOLDER_TYPE_TRASH);
1808 /* TODO: error_handling */
1810 modest_mail_operation_notify_start (self);
1811 modest_mail_operation_xfer_folder (self, folder,
1812 TNY_FOLDER_STORE (trash_folder),
1814 g_object_unref (trash_folder);
1816 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1819 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1821 modest_mail_operation_notify_start (self);
1822 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1823 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1826 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1828 g_object_unref (parent);
1830 g_warning ("%s: could not get parent folder", __FUNCTION__);
1834 /* Notify about operation end */
1835 modest_mail_operation_notify_end (self);
1839 transfer_folder_status_cb (GObject *obj,
1843 ModestMailOperation *self;
1844 ModestMailOperationPrivate *priv;
1845 ModestMailOperationState *state;
1846 XFerFolderAsyncHelper *helper;
1848 g_return_if_fail (status != NULL);
1850 /* Show only the status information we want */
1851 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1854 helper = (XFerFolderAsyncHelper *) user_data;
1855 g_return_if_fail (helper != NULL);
1857 self = helper->mail_op;
1858 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1860 priv->done = status->position;
1861 priv->total = status->of_total;
1863 state = modest_mail_operation_clone_state (self);
1865 /* This is not a GDK lock because we are a Tinymail callback
1866 * which is already GDK locked by Tinymail */
1868 /* no gdk_threads_enter (), CHECKED */
1870 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1872 /* no gdk_threads_leave (), CHECKED */
1874 g_slice_free (ModestMailOperationState, state);
1879 transfer_folder_cb (TnyFolder *folder,
1881 TnyFolderStore *into,
1882 TnyFolder *new_folder,
1886 XFerFolderAsyncHelper *helper;
1887 ModestMailOperation *self = NULL;
1888 ModestMailOperationPrivate *priv = NULL;
1890 helper = (XFerFolderAsyncHelper *) user_data;
1891 g_return_if_fail (helper != NULL);
1893 self = helper->mail_op;
1894 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1897 priv->error = g_error_copy (err);
1899 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1900 } else if (cancelled) {
1901 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1902 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1903 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1904 _("Transference of %s was cancelled."),
1905 tny_folder_get_name (folder));
1908 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1911 /* Notify about operation end */
1912 modest_mail_operation_notify_end (self);
1914 /* If user defined callback function was defined, call it */
1915 if (helper->user_callback) {
1917 /* This is not a GDK lock because we are a Tinymail callback
1918 * which is already GDK locked by Tinymail */
1920 /* no gdk_threads_enter (), CHECKED */
1921 helper->user_callback (self, new_folder, helper->user_data);
1922 /* no gdk_threads_leave () , CHECKED */
1926 g_object_unref (helper->mail_op);
1927 g_slice_free (XFerFolderAsyncHelper, helper);
1932 * This function checks if the new name is a valid name for our local
1933 * folders account. The new name could not be the same than then name
1934 * of any of the mandatory local folders
1936 * We can not rely on tinymail because tinymail does not check the
1937 * name of the virtual folders that the account could have in the case
1938 * that we're doing a rename (because it directly calls Camel which
1939 * knows nothing about our virtual folders).
1941 * In the case of an actual copy/move (i.e. move/copy a folder between
1942 * accounts) tinymail uses the tny_folder_store_create_account which
1943 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1944 * checks the new name of the folder, so this call in that case
1945 * wouldn't be needed. *But* NOTE that if tinymail changes its
1946 * implementation (if folder transfers within the same account is no
1947 * longer implemented as a rename) this call will allow Modest to work
1950 * If the new name is not valid, this function will set the status to
1951 * failed and will set also an error in the mail operation
1954 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1955 TnyFolderStore *into,
1956 const gchar *new_name)
1958 if (TNY_IS_ACCOUNT (into) &&
1959 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1960 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1962 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1963 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1964 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1965 _CS("ckdg_ib_folder_already_exists"));
1972 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1974 TnyFolderStore *parent,
1975 gboolean delete_original,
1976 XferFolderAsyncUserCallback user_callback,
1979 ModestMailOperationPrivate *priv = NULL;
1980 ModestTnyFolderRules parent_rules = 0, rules;
1981 XFerFolderAsyncHelper *helper = NULL;
1982 const gchar *folder_name = NULL;
1983 const gchar *error_msg;
1985 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1986 g_return_if_fail (TNY_IS_FOLDER (folder));
1987 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1989 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1990 folder_name = tny_folder_get_name (folder);
1992 /* Set the error msg */
1993 error_msg = _("mail_in_ui_folder_move_target_error");
1995 /* Get account and set it into mail_operation */
1996 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1997 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1998 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2000 /* Get folder rules */
2001 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2002 if (TNY_IS_FOLDER (parent))
2003 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2005 /* Apply operation constraints */
2006 if ((gpointer) parent == (gpointer) folder ||
2007 (!TNY_IS_FOLDER_STORE (parent)) ||
2008 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2011 } else if (TNY_IS_FOLDER (parent) &&
2012 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2016 } else if (TNY_IS_FOLDER (parent) &&
2017 TNY_IS_FOLDER_STORE (folder) &&
2018 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2019 TNY_FOLDER_STORE (folder))) {
2020 /* Do not move a parent into a child */
2022 } else if (TNY_IS_FOLDER_STORE (parent) &&
2023 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2024 /* Check that the new folder name is not used by any
2027 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2028 /* Check that the new folder name is not used by any
2029 special local folder */
2032 /* Create the helper */
2033 helper = g_slice_new0 (XFerFolderAsyncHelper);
2034 helper->mail_op = g_object_ref (self);
2035 helper->user_callback = user_callback;
2036 helper->user_data = user_data;
2038 /* Move/Copy folder */
2039 modest_mail_operation_notify_start (self);
2040 tny_folder_copy_async (folder,
2042 tny_folder_get_name (folder),
2045 transfer_folder_status_cb,
2051 /* Set status failed and set an error */
2052 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2054 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2057 /* Call the user callback if exists */
2059 user_callback (self, NULL, user_data);
2061 /* Notify the queue */
2062 modest_mail_operation_notify_end (self);
2066 modest_mail_operation_rename_folder (ModestMailOperation *self,
2069 XferFolderAsyncUserCallback user_callback,
2072 ModestMailOperationPrivate *priv;
2073 ModestTnyFolderRules rules;
2074 XFerFolderAsyncHelper *helper;
2076 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2077 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2078 g_return_if_fail (name);
2080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2082 /* Get account and set it into mail_operation */
2083 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2084 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2086 /* Check folder rules */
2087 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2088 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2090 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2093 TnyFolderStore *into;
2095 into = tny_folder_get_folder_store (folder);
2097 /* Check that the new folder name is not used by any
2098 special local folder */
2099 if (new_name_valid_if_local_account (priv, into, name)) {
2100 /* Create the helper */
2101 helper = g_slice_new0 (XFerFolderAsyncHelper);
2102 helper->mail_op = g_object_ref(self);
2103 helper->user_callback = user_callback;
2104 helper->user_data = user_data;
2106 /* Rename. Camel handles folder subscription/unsubscription */
2107 modest_mail_operation_notify_start (self);
2108 tny_folder_copy_async (folder, into, name, TRUE,
2110 transfer_folder_status_cb,
2115 g_object_unref (into);
2120 /* Set status failed and set an error */
2121 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2122 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2123 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2124 _("FIXME: unable to rename"));
2127 user_callback (self, NULL, user_data);
2129 /* Notify about operation end */
2130 modest_mail_operation_notify_end (self);
2133 /* ******************************************************************* */
2134 /* ************************** MSG ACTIONS ************************* */
2135 /* ******************************************************************* */
2138 modest_mail_operation_get_msg (ModestMailOperation *self,
2140 GetMsgAsyncUserCallback user_callback,
2143 GetMsgInfo *helper = NULL;
2145 ModestMailOperationPrivate *priv;
2147 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2148 g_return_if_fail (TNY_IS_HEADER (header));
2150 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2151 folder = tny_header_get_folder (header);
2153 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2157 /* Get account and set it into mail_operation */
2158 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2160 /* Check for cached messages */
2161 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2162 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2164 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2166 /* Create the helper */
2167 helper = g_slice_new0 (GetMsgInfo);
2168 helper->header = g_object_ref (header);
2169 helper->mail_op = g_object_ref (self);
2170 helper->user_callback = user_callback;
2171 helper->user_data = user_data;
2172 helper->destroy_notify = NULL;
2173 helper->last_total_bytes = 0;
2174 helper->sum_total_bytes = 0;
2175 helper->total_bytes = tny_header_get_message_size (header);
2177 modest_mail_operation_notify_start (self);
2179 /* notify about the start of the operation */
2180 ModestMailOperationState *state;
2181 state = modest_mail_operation_clone_state (self);
2184 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2187 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2189 g_object_unref (G_OBJECT (folder));
2193 get_msg_status_cb (GObject *obj,
2197 GetMsgInfo *helper = NULL;
2199 g_return_if_fail (status != NULL);
2201 /* Show only the status information we want */
2202 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2205 helper = (GetMsgInfo *) user_data;
2206 g_return_if_fail (helper != NULL);
2208 /* Notify progress */
2209 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2210 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2214 get_msg_async_cb (TnyFolder *folder,
2220 GetMsgInfo *info = NULL;
2221 ModestMailOperationPrivate *priv = NULL;
2224 info = (GetMsgInfo *) user_data;
2226 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2229 if (info->more_msgs) {
2230 tny_iterator_next (info->more_msgs);
2231 finished = (tny_iterator_is_done (info->more_msgs));
2233 finished = (priv->done == priv->total) ? TRUE : FALSE;
2236 /* If canceled by the user, ignore the error given by Tinymail */
2237 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2243 priv->error = g_error_copy ((const GError *) err);
2244 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2247 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2248 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2251 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2252 /* Set the success status before calling the user callback */
2253 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2257 /* Call the user callback */
2258 if (info->user_callback)
2259 info->user_callback (info->mail_op, info->header, canceled,
2260 msg, err, info->user_data);
2262 /* Notify about operation end if this is the last callback */
2264 /* Free user data */
2265 if (info->destroy_notify)
2266 info->destroy_notify (info->user_data);
2268 /* Notify about operation end */
2269 modest_mail_operation_notify_end (info->mail_op);
2272 if (info->more_msgs)
2273 g_object_unref (info->more_msgs);
2274 g_object_unref (info->header);
2275 g_object_unref (info->mail_op);
2276 g_slice_free (GetMsgInfo, info);
2277 } else if (info->more_msgs) {
2278 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2279 TnyFolder *folder = tny_header_get_folder (header);
2281 g_object_unref (info->header);
2282 info->header = g_object_ref (header);
2284 /* Retrieve the next message */
2285 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2287 g_object_unref (header);
2288 g_object_unref (folder);
2290 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2295 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2296 TnyList *header_list,
2297 GetMsgAsyncUserCallback user_callback,
2299 GDestroyNotify notify)
2301 ModestMailOperationPrivate *priv = NULL;
2303 TnyIterator *iter = NULL;
2304 gboolean has_uncached_messages;
2306 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2308 /* Init mail operation */
2309 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2310 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2312 priv->total = tny_list_get_length(header_list);
2314 /* Check uncached messages */
2315 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2316 !has_uncached_messages && !tny_iterator_is_done (iter);
2317 tny_iterator_next (iter)) {
2320 header = (TnyHeader *) tny_iterator_get_current (iter);
2321 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2322 has_uncached_messages = TRUE;
2323 g_object_unref (header);
2325 g_object_unref (iter);
2326 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2328 /* Get account and set it into mail_operation */
2329 if (tny_list_get_length (header_list) >= 1) {
2330 TnyIterator *iterator = tny_list_create_iterator (header_list);
2331 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2333 TnyFolder *folder = tny_header_get_folder (header);
2335 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2336 g_object_unref (folder);
2338 g_object_unref (header);
2340 g_object_unref (iterator);
2343 msg_list_size = compute_message_list_size (header_list);
2345 modest_mail_operation_notify_start (self);
2346 iter = tny_list_create_iterator (header_list);
2347 if (!tny_iterator_is_done (iter)) {
2348 /* notify about the start of the operation */
2349 ModestMailOperationState *state;
2350 state = modest_mail_operation_clone_state (self);
2353 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2356 GetMsgInfo *msg_info = NULL;
2357 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2358 TnyFolder *folder = tny_header_get_folder (header);
2360 /* Create the message info */
2361 msg_info = g_slice_new0 (GetMsgInfo);
2362 msg_info->mail_op = g_object_ref (self);
2363 msg_info->header = g_object_ref (header);
2364 msg_info->more_msgs = g_object_ref (iter);
2365 msg_info->user_callback = user_callback;
2366 msg_info->user_data = user_data;
2367 msg_info->destroy_notify = notify;
2368 msg_info->last_total_bytes = 0;
2369 msg_info->sum_total_bytes = 0;
2370 msg_info->total_bytes = msg_list_size;
2372 /* The callback will call it per each header */
2373 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2375 /* Free and go on */
2376 g_object_unref (header);
2377 g_object_unref (folder);
2378 g_slice_free (ModestMailOperationState, state);
2380 g_object_unref (iter);
2385 remove_msgs_async_cb (TnyFolder *folder,
2390 gboolean expunge, leave_on_server;
2391 const gchar *account_name;
2393 TnyAccount *account;
2394 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2395 ModestMailOperation *self;
2396 ModestMailOperationPrivate *priv;
2398 self = (ModestMailOperation *) user_data;
2399 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2401 if (canceled || err) {
2402 /* If canceled by the user, ignore the error given by Tinymail */
2404 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2406 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2407 priv->error = g_error_copy ((const GError *) err);
2408 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2411 modest_mail_operation_notify_end (self);
2412 g_object_unref (self);
2416 account = tny_folder_get_account (folder);
2417 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2419 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2421 proto = tny_account_get_proto (account);
2422 g_object_unref (account);
2425 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2427 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2428 modest_tny_folder_is_remote_folder (folder) == FALSE)
2434 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2439 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2441 gboolean remove_to_trash /*ignored*/)
2443 TnyFolder *folder = NULL;
2444 ModestMailOperationPrivate *priv;
2445 TnyIterator *iter = NULL;
2446 TnyHeader *header = NULL;
2447 TnyList *remove_headers = NULL;
2448 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2450 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2451 g_return_if_fail (TNY_IS_LIST (headers));
2453 if (remove_to_trash)
2454 g_warning ("remove to trash is not implemented");
2456 if (tny_list_get_length(headers) == 0) {
2457 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2458 goto cleanup; /* nothing to do */
2461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2462 remove_headers = g_object_ref(headers);
2464 /* Get folder from first header and sync it */
2465 iter = tny_list_create_iterator (headers);
2466 header = TNY_HEADER (tny_iterator_get_current (iter));
2468 folder = tny_header_get_folder (header);
2469 if (!TNY_IS_FOLDER(folder)) {
2470 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2474 /* Don't remove messages that are being sent */
2475 if (modest_tny_folder_is_local_folder (folder)) {
2476 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2478 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2479 TnyTransportAccount *traccount = NULL;
2480 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2481 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2483 ModestTnySendQueueStatus status;
2484 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2485 TnyIterator *iter = tny_list_create_iterator(headers);
2486 g_object_unref(remove_headers);
2487 remove_headers = TNY_LIST(tny_simple_list_new());
2488 while (!tny_iterator_is_done(iter)) {
2490 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2491 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2492 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2493 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2494 tny_list_append(remove_headers, G_OBJECT(hdr));
2496 g_object_unref(hdr);
2498 tny_iterator_next(iter);
2500 g_object_unref(iter);
2501 g_object_unref(traccount);
2505 /* Get account and set it into mail_operation */
2506 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2507 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2508 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2510 /* remove message from folder */
2511 modest_mail_operation_notify_start (self);
2512 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2513 NULL, g_object_ref (self));
2517 g_object_unref (remove_headers);
2519 g_object_unref (header);
2521 g_object_unref (iter);
2523 g_object_unref (folder);
2527 notify_progress_of_multiple_messages (ModestMailOperation *self,
2529 gint *last_total_bytes,
2530 gint *sum_total_bytes,
2532 gboolean increment_done)
2534 ModestMailOperationPrivate *priv;
2535 ModestMailOperationState *state;
2536 gboolean is_num_bytes = FALSE;
2538 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2540 /* We know that tinymail sends us information about
2541 * transferred bytes with this particular message
2543 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2544 * I just added the 'if' so we don't get runtime warning)
2546 if (status->message)
2547 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2549 state = modest_mail_operation_clone_state (self);
2550 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2551 /* We know that we're in a different message when the
2552 total number of bytes to transfer is different. Of
2553 course it could fail if we're transferring messages
2554 of the same size, but this is a workarround */
2555 if (status->of_total != *last_total_bytes) {
2556 /* We need to increment the done when there is
2557 no information about each individual
2558 message, we need to do this in message
2559 transfers, and we don't do it for getting
2563 *sum_total_bytes += *last_total_bytes;
2564 *last_total_bytes = status->of_total;
2566 state->bytes_done += status->position + *sum_total_bytes;
2567 state->bytes_total = total_bytes;
2569 /* Notify the status change. Only notify about changes
2570 referred to bytes */
2571 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2575 g_slice_free (ModestMailOperationState, state);
2579 transfer_msgs_status_cb (GObject *obj,
2583 XFerMsgsAsyncHelper *helper;
2585 g_return_if_fail (status != NULL);
2587 /* Show only the status information we want */
2588 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2591 helper = (XFerMsgsAsyncHelper *) user_data;
2592 g_return_if_fail (helper != NULL);
2594 /* Notify progress */
2595 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2596 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2601 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2603 XFerMsgsAsyncHelper *helper;
2604 ModestMailOperation *self;
2605 ModestMailOperationPrivate *priv;
2606 gboolean finished = TRUE;
2608 helper = (XFerMsgsAsyncHelper *) user_data;
2609 self = helper->mail_op;
2611 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2614 priv->error = g_error_copy (err);
2616 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2617 } else if (cancelled) {
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2620 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2621 _("Error trying to refresh the contents of %s"),
2622 tny_folder_get_name (folder));
2623 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2624 if (helper->more_msgs) {
2625 /* We'll transfer the next message in the list */
2626 tny_iterator_next (helper->more_msgs);
2627 if (!tny_iterator_is_done (helper->more_msgs)) {
2628 GObject *next_header;
2629 g_object_unref (helper->headers);
2630 helper->headers = tny_simple_list_new ();
2631 next_header = tny_iterator_get_current (helper->more_msgs);
2632 tny_list_append (helper->headers, next_header);
2633 g_object_unref (next_header);
2640 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2646 /* Update folder counts */
2647 tny_folder_poke_status (folder);
2648 tny_folder_poke_status (helper->dest_folder);
2650 /* Notify about operation end */
2651 modest_mail_operation_notify_end (self);
2653 /* If user defined callback function was defined, call it */
2654 if (helper->user_callback) {
2655 /* This is not a GDK lock because we are a Tinymail callback and
2656 * Tinymail already acquires the Gdk lock */
2658 /* no gdk_threads_enter (), CHECKED */
2659 helper->user_callback (self, helper->user_data);
2660 /* no gdk_threads_leave (), CHECKED */
2664 if (helper->more_msgs)
2665 g_object_unref (helper->more_msgs);
2666 if (helper->headers)
2667 g_object_unref (helper->headers);
2668 if (helper->dest_folder)
2669 g_object_unref (helper->dest_folder);
2670 if (helper->mail_op)
2671 g_object_unref (helper->mail_op);
2672 g_slice_free (XFerMsgsAsyncHelper, helper);
2674 /* Transfer more messages */
2675 tny_folder_transfer_msgs_async (folder,
2677 helper->dest_folder,
2680 transfer_msgs_status_cb,
2686 compute_message_list_size (TnyList *headers)
2691 iter = tny_list_create_iterator (headers);
2692 while (!tny_iterator_is_done (iter)) {
2693 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2694 size += tny_header_get_message_size (header);
2695 g_object_unref (header);
2696 tny_iterator_next (iter);
2698 g_object_unref (iter);
2704 compute_message_array_size (GPtrArray *headers)
2709 for (i = 0; i < headers->len; i++) {
2710 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2711 size += tny_header_get_message_size (header);
2719 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2722 gboolean delete_original,
2723 XferMsgsAsyncUserCallback user_callback,
2726 ModestMailOperationPrivate *priv = NULL;
2727 TnyIterator *iter = NULL;
2728 TnyFolder *src_folder = NULL;
2729 XFerMsgsAsyncHelper *helper = NULL;
2730 TnyHeader *header = NULL;
2731 ModestTnyFolderRules rules = 0;
2732 TnyAccount *dst_account = NULL;
2733 gboolean leave_on_server;
2735 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2736 g_return_if_fail (headers && TNY_IS_LIST (headers));
2737 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2739 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2740 priv->total = tny_list_get_length (headers);
2742 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2743 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2745 /* Apply folder rules */
2746 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2747 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2748 /* Set status failed and set an error */
2749 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2750 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2751 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2752 _CS("ckct_ib_unable_to_paste_here"));
2753 /* Notify the queue */
2754 modest_mail_operation_notify_end (self);
2758 /* Get source folder */
2759 iter = tny_list_create_iterator (headers);
2760 header = TNY_HEADER (tny_iterator_get_current (iter));
2762 src_folder = tny_header_get_folder (header);
2763 g_object_unref (header);
2765 g_object_unref (iter);
2767 if (src_folder == NULL) {
2768 /* Notify the queue */
2769 modest_mail_operation_notify_end (self);
2771 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2776 /* Check folder source and destination */
2777 if (src_folder == folder) {
2778 /* Set status failed and set an error */
2779 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2780 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2781 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2782 _("mail_in_ui_folder_copy_target_error"));
2784 /* Notify the queue */
2785 modest_mail_operation_notify_end (self);
2788 g_object_unref (src_folder);
2792 /* Create the helper */
2793 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2794 helper->mail_op = g_object_ref(self);
2795 helper->dest_folder = g_object_ref(folder);
2796 helper->user_callback = user_callback;
2797 helper->user_data = user_data;
2798 helper->delete = delete_original;
2799 helper->last_total_bytes = 0;
2800 helper->sum_total_bytes = 0;
2801 helper->total_bytes = compute_message_list_size (headers);
2803 /* Get account and set it into mail_operation */
2804 priv->account = modest_tny_folder_get_account (src_folder);
2805 dst_account = modest_tny_folder_get_account (folder);
2807 if (priv->account == dst_account) {
2808 /* Transfer all messages at once using the fast
2809 * method. Note that depending on the server this
2810 * might not be that fast, and might not be
2811 * user-cancellable either */
2812 helper->headers = g_object_ref (headers);
2813 helper->more_msgs = NULL;
2815 /* Transfer messages one by one so the user can cancel
2818 helper->headers = tny_simple_list_new ();
2819 helper->more_msgs = tny_list_create_iterator (headers);
2820 hdr = tny_iterator_get_current (helper->more_msgs);
2821 tny_list_append (helper->headers, hdr);
2822 g_object_unref (hdr);
2825 /* If leave_on_server is set to TRUE then don't use
2826 delete_original, we always pass FALSE. This is because
2827 otherwise tinymail will try to sync the source folder and
2828 this could cause an error if we're offline while
2829 transferring an already downloaded message from a POP
2831 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2832 MODEST_PROTOCOL_STORE_POP) {
2833 const gchar *account_name;
2835 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2836 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2839 leave_on_server = FALSE;
2842 modest_mail_operation_notify_start (self);
2843 tny_folder_transfer_msgs_async (src_folder,
2846 (leave_on_server) ? FALSE : delete_original,
2848 transfer_msgs_status_cb,
2850 g_object_unref (src_folder);
2851 g_object_unref (dst_account);
2856 on_refresh_folder (TnyFolder *folder,
2861 RefreshAsyncHelper *helper = NULL;
2862 ModestMailOperation *self = NULL;
2863 ModestMailOperationPrivate *priv = NULL;
2865 helper = (RefreshAsyncHelper *) user_data;
2866 self = helper->mail_op;
2867 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2869 g_return_if_fail(priv!=NULL);
2872 priv->error = g_error_copy (error);
2873 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2878 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2879 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2880 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2881 _("Error trying to refresh the contents of %s"),
2882 tny_folder_get_name (folder));
2886 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2889 /* Call user defined callback, if it exists */
2890 if (helper->user_callback) {
2892 /* This is not a GDK lock because we are a Tinymail callback and
2893 * Tinymail already acquires the Gdk lock */
2894 helper->user_callback (self, folder, helper->user_data);
2898 g_slice_free (RefreshAsyncHelper, helper);
2900 /* Notify about operation end */
2901 modest_mail_operation_notify_end (self);
2902 g_object_unref(self);
2906 on_refresh_folder_status_update (GObject *obj,
2910 RefreshAsyncHelper *helper = NULL;
2911 ModestMailOperation *self = NULL;
2912 ModestMailOperationPrivate *priv = NULL;
2913 ModestMailOperationState *state;
2915 g_return_if_fail (user_data != NULL);
2916 g_return_if_fail (status != NULL);
2918 /* Show only the status information we want */
2919 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2922 helper = (RefreshAsyncHelper *) user_data;
2923 self = helper->mail_op;
2924 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2926 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2928 priv->done = status->position;
2929 priv->total = status->of_total;
2931 state = modest_mail_operation_clone_state (self);
2933 /* This is not a GDK lock because we are a Tinymail callback and
2934 * Tinymail already acquires the Gdk lock */
2935 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2937 g_slice_free (ModestMailOperationState, state);
2941 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2943 RefreshAsyncUserCallback user_callback,
2946 ModestMailOperationPrivate *priv = NULL;
2947 RefreshAsyncHelper *helper = NULL;
2949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2951 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2953 /* Get account and set it into mail_operation */
2954 priv->account = modest_tny_folder_get_account (folder);
2955 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2957 /* Create the helper */
2958 helper = g_slice_new0 (RefreshAsyncHelper);
2959 helper->mail_op = g_object_ref(self);
2960 helper->user_callback = user_callback;
2961 helper->user_data = user_data;
2963 modest_mail_operation_notify_start (self);
2965 /* notify that the operation was started */
2966 ModestMailOperationState *state;
2967 state = modest_mail_operation_clone_state (self);
2970 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2973 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2975 tny_folder_refresh_async (folder,
2977 on_refresh_folder_status_update,
2982 run_queue_stop (ModestTnySendQueue *queue,
2983 ModestMailOperation *self)
2985 ModestMailOperationPrivate *priv;
2987 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2988 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2989 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2991 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2993 modest_mail_operation_notify_end (self);
2994 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
2995 g_object_unref (self);
2998 modest_mail_operation_run_queue (ModestMailOperation *self,
2999 ModestTnySendQueue *queue)
3001 ModestMailOperationPrivate *priv;
3003 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3004 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3005 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3007 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3008 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3009 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3011 modest_mail_operation_notify_start (self);
3012 g_object_ref (self);
3013 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3017 sync_folder_finish_callback (TnyFolder *self,
3023 ModestMailOperation *mail_op;
3024 ModestMailOperationPrivate *priv;
3026 mail_op = (ModestMailOperation *) user_data;
3027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3029 /* If canceled by the user, ignore the error given by Tinymail */
3031 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3033 /* If the operation was a sync then the status is
3034 failed, but if it's part of another operation then
3035 just set it as finished with errors */
3036 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3037 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3039 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3040 priv->error = g_error_copy ((const GError *) err);
3041 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3043 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3046 modest_mail_operation_notify_end (mail_op);
3047 g_object_unref (mail_op);
3051 modest_mail_operation_sync_folder (ModestMailOperation *self,
3052 TnyFolder *folder, gboolean expunge)
3054 ModestMailOperationPrivate *priv;
3056 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3057 g_return_if_fail (TNY_IS_FOLDER (folder));
3058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3060 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3061 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3062 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3064 modest_mail_operation_notify_start (self);
3065 g_object_ref (self);
3066 tny_folder_sync_async (folder, expunge,
3067 (TnyFolderCallback) sync_folder_finish_callback,
3072 modest_mail_operation_notify_start (ModestMailOperation *self)
3074 ModestMailOperationPrivate *priv = NULL;
3076 g_return_if_fail (self);
3078 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3080 /* Ensure that all the fields are filled correctly */
3081 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3083 /* Notify the observers about the mail operation. We do not
3084 wrapp this emission because we assume that this function is
3085 always called from within the main lock */
3086 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3091 * It's used by the mail operation queue to notify the observers
3092 * attached to that signal that the operation finished. We need to use
3093 * that because tinymail does not give us the progress of a given
3094 * operation when it finishes (it directly calls the operation
3098 modest_mail_operation_notify_end (ModestMailOperation *self)
3100 ModestMailOperationPrivate *priv = NULL;
3102 g_return_if_fail (self);
3104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3106 /* Notify the observers about the mail operation end. We do
3107 not wrapp this emission because we assume that this
3108 function is always called from within the main lock */
3109 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3111 /* Remove the error user data */
3112 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3113 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3117 modest_mail_operation_get_account (ModestMailOperation *self)
3119 ModestMailOperationPrivate *priv = NULL;
3121 g_return_val_if_fail (self, NULL);
3123 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3125 return (priv->account) ? g_object_ref (priv->account) : NULL;
3129 modest_mail_operation_noop (ModestMailOperation *self)
3131 ModestMailOperationPrivate *priv = NULL;
3133 g_return_if_fail (self);
3135 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3136 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3137 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3141 /* This mail operation does nothing actually */
3142 modest_mail_operation_notify_start (self);
3143 modest_mail_operation_notify_end (self);
3148 modest_mail_operation_to_string (ModestMailOperation *self)
3150 const gchar *type, *status, *account_id;
3151 ModestMailOperationPrivate *priv = NULL;
3153 g_return_val_if_fail (self, NULL);
3155 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3157 /* new operations don't have anything interesting */
3158 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3159 return g_strdup_printf ("%p <new operation>", self);
3161 switch (priv->op_type) {
3162 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3163 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3164 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3165 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3166 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3167 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3168 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3169 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3170 default: type = "UNEXPECTED"; break;
3173 switch (priv->status) {
3174 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3175 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3176 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3177 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3178 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3179 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3180 default: status= "UNEXPECTED"; break;
3183 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3185 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3186 priv->done, priv->total,
3187 priv->error && priv->error->message ? priv->error->message : "");