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;
792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
795 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
796 modest_mail_operation_notify_end (self);
800 /* Call mail operation */
801 modest_mail_operation_send_mail (self, info->transport_account, msg);
803 if (info->draft_msg != 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 tny_folder_remove_msg (src_folder, header, NULL);
850 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
851 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
853 g_object_unref (folder);
858 g_object_unref (header);
862 g_object_unref (info->draft_msg);
864 g_object_unref (draft_folder);
866 g_object_unref (outbox_folder);
867 if (info->transport_account)
868 g_object_unref (info->transport_account);
869 g_slice_free (SendNewMailInfo, info);
873 modest_mail_operation_send_new_mail (ModestMailOperation *self,
874 TnyTransportAccount *transport_account,
876 const gchar *from, const gchar *to,
877 const gchar *cc, const gchar *bcc,
878 const gchar *subject, const gchar *plain_body,
879 const gchar *html_body,
880 const GList *attachments_list,
881 const GList *images_list,
882 TnyHeaderFlags priority_flags)
884 ModestMailOperationPrivate *priv = NULL;
885 SendNewMailInfo *info;
887 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
888 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
890 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
891 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
892 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
893 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
895 /* Check parametters */
897 /* Set status failed and set an error */
898 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
899 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
900 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
901 _("Error trying to send a mail. You need to set at least one recipient"));
904 info = g_slice_new0 (SendNewMailInfo);
905 info->transport_account = transport_account;
906 if (transport_account)
907 g_object_ref (transport_account);
908 info->draft_msg = draft_msg;
910 g_object_ref (draft_msg);
913 modest_mail_operation_notify_start (self);
914 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
915 attachments_list, images_list, priority_flags,
916 modest_mail_operation_send_new_mail_cb, info);
922 TnyTransportAccount *transport_account;
924 SaveToDraftstCallback callback;
928 ModestMailOperation *mailop;
929 } SaveToDraftsAddMsgInfo;
932 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
937 ModestMailOperationPrivate *priv = NULL;
938 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
940 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
943 g_warning ("%s: priv->error != NULL", __FUNCTION__);
944 g_error_free(priv->error);
947 priv->error = (err == NULL) ? NULL : g_error_copy(err);
949 if ((!priv->error) && (info->draft_msg != NULL)) {
950 TnyHeader *header = tny_msg_get_header (info->draft_msg);
951 TnyFolder *src_folder = tny_header_get_folder (header);
953 /* Remove the old draft */
954 tny_folder_remove_msg (src_folder, header, NULL);
956 /* Synchronize to expunge and to update the msg counts */
957 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
958 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
960 g_object_unref (G_OBJECT(header));
961 g_object_unref (G_OBJECT(src_folder));
965 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
967 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
969 /* Call the user callback */
971 info->callback (info->mailop, info->msg, info->user_data);
973 if (info->transport_account)
974 g_object_unref (G_OBJECT(info->transport_account));
976 g_object_unref (G_OBJECT (info->draft_msg));
978 g_object_unref (G_OBJECT(info->drafts));
980 g_object_unref (G_OBJECT (info->msg));
982 modest_mail_operation_notify_end (info->mailop);
983 g_object_unref(info->mailop);
984 g_slice_free (SaveToDraftsAddMsgInfo, info);
989 TnyTransportAccount *transport_account;
991 SaveToDraftstCallback callback;
996 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1000 TnyFolder *drafts = NULL;
1001 ModestMailOperationPrivate *priv = NULL;
1002 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1004 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1007 if (!(priv->error)) {
1008 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1009 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1010 "modest: failed to create a new msg\n");
1013 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1014 TNY_FOLDER_TYPE_DRAFTS);
1015 if (!drafts && !(priv->error)) {
1016 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1017 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1018 "modest: failed to create a new msg\n");
1023 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1024 cb_info->transport_account = g_object_ref(info->transport_account);
1025 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1026 cb_info->callback = info->callback;
1027 cb_info->user_data = info->user_data;
1028 cb_info->drafts = g_object_ref(drafts);
1029 cb_info->msg = g_object_ref(msg);
1030 cb_info->mailop = g_object_ref(self);
1031 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1034 /* Call the user callback */
1035 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1037 info->callback (self, msg, info->user_data);
1038 modest_mail_operation_notify_end (self);
1042 g_object_unref (G_OBJECT(drafts));
1043 if (info->draft_msg)
1044 g_object_unref (G_OBJECT (info->draft_msg));
1045 if (info->transport_account)
1046 g_object_unref (G_OBJECT(info->transport_account));
1047 g_slice_free (SaveToDraftsInfo, info);
1051 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1052 TnyTransportAccount *transport_account,
1054 const gchar *from, const gchar *to,
1055 const gchar *cc, const gchar *bcc,
1056 const gchar *subject, const gchar *plain_body,
1057 const gchar *html_body,
1058 const GList *attachments_list,
1059 const GList *images_list,
1060 TnyHeaderFlags priority_flags,
1061 SaveToDraftstCallback callback,
1064 ModestMailOperationPrivate *priv = NULL;
1065 SaveToDraftsInfo *info = NULL;
1067 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1068 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1070 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1072 /* Get account and set it into mail_operation */
1073 priv->account = g_object_ref (transport_account);
1074 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1076 info = g_slice_new0 (SaveToDraftsInfo);
1077 info->transport_account = g_object_ref (transport_account);
1078 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1079 info->callback = callback;
1080 info->user_data = user_data;
1082 modest_mail_operation_notify_start (self);
1083 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1084 attachments_list, images_list, priority_flags,
1085 modest_mail_operation_save_to_drafts_cb, info);
1090 ModestMailOperation *mail_op;
1091 TnyMimePart *mime_part;
1093 GetMimePartSizeCallback callback;
1095 } GetMimePartSizeInfo;
1097 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1098 /* We use this folder observer to track the headers that have been
1099 * added to a folder */
1102 TnyList *new_headers;
1103 } InternalFolderObserver;
1106 GObjectClass parent;
1107 } InternalFolderObserverClass;
1109 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1111 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1112 internal_folder_observer,
1114 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1118 foreach_add_item (gpointer header, gpointer user_data)
1120 tny_list_prepend (TNY_LIST (user_data),
1121 g_object_ref (G_OBJECT (header)));
1124 /* This is the method that looks for new messages in a folder */
1126 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1128 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1130 TnyFolderChangeChanged changed;
1132 changed = tny_folder_change_get_changed (change);
1134 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1137 /* Get added headers */
1138 list = tny_simple_list_new ();
1139 tny_folder_change_get_added_headers (change, list);
1141 /* Add them to the folder observer */
1142 tny_list_foreach (list, foreach_add_item,
1143 derived->new_headers);
1145 g_object_unref (G_OBJECT (list));
1150 internal_folder_observer_init (InternalFolderObserver *self)
1152 self->new_headers = tny_simple_list_new ();
1155 internal_folder_observer_finalize (GObject *object)
1157 InternalFolderObserver *self;
1159 self = (InternalFolderObserver *) object;
1160 g_object_unref (self->new_headers);
1162 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1165 tny_folder_observer_init (TnyFolderObserverIface *iface)
1167 iface->update = internal_folder_observer_update;
1170 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1172 GObjectClass *object_class;
1174 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1175 object_class = (GObjectClass*) klass;
1176 object_class->finalize = internal_folder_observer_finalize;
1181 ModestMailOperation *mail_op;
1182 gchar *account_name;
1183 UpdateAccountCallback callback;
1188 TnyFolderObserver *inbox_observer;
1189 RetrieveAllCallback retrieve_all_cb;
1190 gboolean interactive;
1191 } UpdateAccountInfo;
1195 destroy_update_account_info (UpdateAccountInfo *info)
1197 g_free (info->account_name);
1198 g_object_unref (info->folders);
1199 g_object_unref (info->mail_op);
1200 g_slice_free (UpdateAccountInfo, info);
1204 update_account_get_msg_async_cb (TnyFolder *folder,
1210 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1212 /* Just delete the helper. Don't do anything with the new
1213 msg. There is also no need to check for errors */
1214 g_object_unref (msg_info->mail_op);
1215 g_object_unref (msg_info->header);
1216 g_slice_free (GetMsgInfo, msg_info);
1220 update_account_notify_user_and_free (UpdateAccountInfo *info,
1221 TnyList *new_headers)
1223 /* Set the account back to not busy */
1224 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1225 info->account_name, FALSE);
1229 info->callback (info->mail_op, new_headers, info->user_data);
1231 /* Mail operation end */
1232 modest_mail_operation_notify_end (info->mail_op);
1236 g_object_unref (new_headers);
1237 destroy_update_account_info (info);
1241 inbox_refreshed_cb (TnyFolder *inbox,
1246 UpdateAccountInfo *info;
1247 ModestMailOperationPrivate *priv;
1248 TnyIterator *new_headers_iter;
1249 GPtrArray *new_headers_array = NULL;
1250 gint max_size, retrieve_limit, i;
1251 ModestAccountMgr *mgr;
1252 ModestAccountRetrieveType retrieve_type;
1253 TnyList *new_headers = NULL;
1254 gboolean headers_only, ignore_limit;
1255 TnyTransportAccount *transport_account = NULL;
1257 info = (UpdateAccountInfo *) user_data;
1258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1259 mgr = modest_runtime_get_account_mgr ();
1261 if (canceled || err) {
1262 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1264 priv->error = g_error_copy (err);
1266 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1267 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1269 /* Notify the user about the error and then exit */
1270 update_account_notify_user_and_free (info, NULL);
1275 /* Try to send anyway */
1279 /* Get the message max size */
1280 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1281 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1283 max_size = G_MAXINT;
1285 max_size = max_size * KB;
1287 /* Create the new headers array. We need it to sort the
1288 new headers by date */
1289 new_headers_array = g_ptr_array_new ();
1290 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1291 while (!tny_iterator_is_done (new_headers_iter)) {
1292 TnyHeader *header = NULL;
1294 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1295 /* Apply per-message size limits */
1296 if (tny_header_get_message_size (header) < max_size)
1297 g_ptr_array_add (new_headers_array, g_object_ref (header));
1299 g_object_unref (header);
1300 tny_iterator_next (new_headers_iter);
1302 g_object_unref (new_headers_iter);
1303 tny_folder_remove_observer (inbox, info->inbox_observer);
1304 g_object_unref (info->inbox_observer);
1305 info->inbox_observer = NULL;
1307 /* Update the last updated key, even if we don't have to get new headers */
1308 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1310 if (new_headers_array->len == 0)
1313 /* Get per-account message amount retrieval limit */
1314 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1315 if (retrieve_limit == 0)
1316 retrieve_limit = G_MAXINT;
1318 /* Get per-account retrieval type */
1319 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1320 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1323 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1325 /* Ask the users if they want to retrieve all the messages
1326 even though the limit was exceeded */
1327 ignore_limit = FALSE;
1328 if (new_headers_array->len > retrieve_limit) {
1329 /* Ask the user if a callback has been specified and
1330 if the mail operation has a source (this means that
1331 was invoked by the user and not automatically by a
1333 if (info->retrieve_all_cb && priv->source)
1334 ignore_limit = info->retrieve_all_cb (priv->source,
1335 new_headers_array->len,
1339 if (!headers_only) {
1341 const gint msg_list_size = compute_message_array_size (new_headers_array);
1345 priv->total = new_headers_array->len;
1347 priv->total = MIN (new_headers_array->len, retrieve_limit);
1348 while (msg_num < priv->total) {
1349 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1350 TnyFolder *folder = tny_header_get_folder (header);
1351 GetMsgInfo *msg_info;
1353 /* Create the message info */
1354 msg_info = g_slice_new0 (GetMsgInfo);
1355 msg_info->mail_op = g_object_ref (info->mail_op);
1356 msg_info->header = g_object_ref (header);
1357 msg_info->total_bytes = msg_list_size;
1359 /* Get message in an async way */
1360 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1361 get_msg_status_cb, msg_info);
1363 g_object_unref (folder);
1369 /* Copy the headers to a list and free the array */
1370 new_headers = tny_simple_list_new ();
1371 for (i=0; i < new_headers_array->len; i++) {
1372 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1373 tny_list_append (new_headers, G_OBJECT (header));
1375 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1376 g_ptr_array_free (new_headers_array, FALSE);
1379 /* Get the transport account */
1380 transport_account = (TnyTransportAccount *)
1381 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1382 info->account_name);
1384 if (transport_account) {
1385 ModestTnySendQueue *send_queue;
1389 send_queue = modest_runtime_get_send_queue (transport_account);
1390 g_object_unref (transport_account);
1392 /* Get outbox folder */
1393 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1394 if (outbox) { /* this could fail in some cases */
1395 num_messages = tny_folder_get_all_count (outbox);
1396 g_object_unref (outbox);
1398 g_warning ("%s: could not get outbox", __FUNCTION__);
1402 if (num_messages != 0) {
1403 /* Reenable suspended items */
1404 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1407 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1408 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1413 /* Check if the operation was a success */
1415 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1417 /* Call the user callback and free */
1418 update_account_notify_user_and_free (info, new_headers);
1422 recurse_folders_async_cb (TnyFolderStore *folder_store,
1428 UpdateAccountInfo *info;
1429 ModestMailOperationPrivate *priv;
1431 info = (UpdateAccountInfo *) user_data;
1432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1434 if (err || canceled) {
1435 /* If the error was previosly set by another callback
1436 don't set it again */
1438 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1440 priv->error = g_error_copy (err);
1442 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1443 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1447 /* We're not getting INBOX children if we don't want to poke all */
1448 TnyIterator *iter = tny_list_create_iterator (list);
1449 while (!tny_iterator_is_done (iter)) {
1450 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1452 /* Add to the list of all folders */
1453 tny_list_append (info->folders, (GObject *) folder);
1455 if (info->poke_all) {
1456 TnyList *folders = tny_simple_list_new ();
1457 /* Add pending call */
1458 info->pending_calls++;
1460 tny_folder_store_get_folders_async (folder, folders, NULL,
1461 recurse_folders_async_cb,
1463 g_object_unref (folders);
1466 g_object_unref (G_OBJECT (folder));
1468 tny_iterator_next (iter);
1470 g_object_unref (G_OBJECT (iter));
1473 /* Remove my own pending call */
1474 info->pending_calls--;
1476 /* This means that we have all the folders */
1477 if (info->pending_calls == 0) {
1478 TnyIterator *iter_all_folders;
1479 TnyFolder *inbox = NULL;
1481 /* If there was any error do not continue */
1483 update_account_notify_user_and_free (info, NULL);
1487 iter_all_folders = tny_list_create_iterator (info->folders);
1489 /* Do a poke status over all folders */
1490 while (!tny_iterator_is_done (iter_all_folders) &&
1491 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1492 TnyFolder *folder = NULL;
1494 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1496 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1497 /* Get a reference to the INBOX */
1498 inbox = g_object_ref (folder);
1500 /* Issue a poke status over the folder */
1502 tny_folder_poke_status (folder);
1505 /* Free and go to next */
1506 g_object_unref (folder);
1507 tny_iterator_next (iter_all_folders);
1509 g_object_unref (iter_all_folders);
1511 /* Refresh the INBOX */
1513 /* Refresh the folder. Our observer receives
1514 * the new emails during folder refreshes, so
1515 * we can use observer->new_headers
1517 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1518 tny_folder_add_observer (inbox, info->inbox_observer);
1520 /* Refresh the INBOX */
1521 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1522 g_object_unref (inbox);
1524 /* We could not perform the inbox refresh but
1525 we'll try to send mails anyway */
1526 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1532 modest_mail_operation_update_account (ModestMailOperation *self,
1533 const gchar *account_name,
1535 gboolean interactive,
1536 RetrieveAllCallback retrieve_all_cb,
1537 UpdateAccountCallback callback,
1540 UpdateAccountInfo *info = NULL;
1541 ModestMailOperationPrivate *priv = NULL;
1542 ModestTnyAccountStore *account_store = NULL;
1544 ModestMailOperationState *state;
1546 /* Init mail operation */
1547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1550 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1551 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1553 /* Get the store account */
1554 account_store = modest_runtime_get_account_store ();
1556 modest_tny_account_store_get_server_account (account_store,
1558 TNY_ACCOUNT_TYPE_STORE);
1560 /* The above function could return NULL */
1561 if (!priv->account) {
1562 /* Check if the operation was a success */
1563 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1564 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1566 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1568 /* Call the user callback */
1570 callback (self, NULL, user_data);
1572 /* Notify about operation end */
1573 modest_mail_operation_notify_end (self);
1578 /* We have once seen priv->account getting finalized during this code,
1579 * therefore adding a reference (bug #82296) */
1581 g_object_ref (priv->account);
1583 /* Create the helper object */
1584 info = g_slice_new0 (UpdateAccountInfo);
1585 info->pending_calls = 1;
1586 info->folders = tny_simple_list_new ();
1587 info->mail_op = g_object_ref (self);
1588 info->poke_all = poke_all;
1589 info->interactive = interactive;
1590 info->account_name = g_strdup (account_name);
1591 info->callback = callback;
1592 info->user_data = user_data;
1593 info->retrieve_all_cb = retrieve_all_cb;
1595 /* Set account busy */
1596 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1597 modest_mail_operation_notify_start (self);
1599 /* notify about the start of the operation */
1600 state = modest_mail_operation_clone_state (self);
1604 /* Start notifying progress */
1605 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1606 g_slice_free (ModestMailOperationState, state);
1608 /* Get all folders and continue in the callback */
1609 folders = tny_simple_list_new ();
1610 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1612 recurse_folders_async_cb,
1614 g_object_unref (folders);
1616 g_object_unref (priv->account);
1621 * Used to notify the queue from the main
1622 * loop. We call it inside an idle call to achieve that
1625 idle_notify_queue (gpointer data)
1627 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1629 gdk_threads_enter ();
1630 modest_mail_operation_notify_end (mail_op);
1631 gdk_threads_leave ();
1632 g_object_unref (mail_op);
1638 compare_headers_by_date (gconstpointer a,
1641 TnyHeader **header1, **header2;
1642 time_t sent1, sent2;
1644 header1 = (TnyHeader **) a;
1645 header2 = (TnyHeader **) b;
1647 sent1 = tny_header_get_date_sent (*header1);
1648 sent2 = tny_header_get_date_sent (*header2);
1650 /* We want the most recent ones (greater time_t) at the
1659 /* ******************************************************************* */
1660 /* ************************** STORE ACTIONS ************************* */
1661 /* ******************************************************************* */
1664 ModestMailOperation *mail_op;
1665 CreateFolderUserCallback callback;
1671 create_folder_cb (TnyFolderStore *parent_folder,
1673 TnyFolder *new_folder,
1677 ModestMailOperationPrivate *priv;
1678 CreateFolderInfo *info;
1680 info = (CreateFolderInfo *) user_data;
1681 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1683 if (canceled || err) {
1684 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1686 priv->error = g_error_copy (err);
1688 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1689 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1692 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1695 /* The user will unref the new_folder */
1697 info->callback (info->mail_op, parent_folder,
1698 new_folder, info->user_data);
1700 /* Notify about operation end */
1701 modest_mail_operation_notify_end (info->mail_op);
1704 g_object_unref (info->mail_op);
1705 g_slice_free (CreateFolderInfo, info);
1709 modest_mail_operation_create_folder (ModestMailOperation *self,
1710 TnyFolderStore *parent,
1712 CreateFolderUserCallback callback,
1715 ModestMailOperationPrivate *priv;
1717 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1718 g_return_if_fail (name);
1720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1721 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1722 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1723 g_object_ref (parent) :
1724 modest_tny_folder_get_account (TNY_FOLDER (parent));
1726 /* Check for already existing folder */
1727 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1728 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1729 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1730 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1731 _CS("ckdg_ib_folder_already_exists"));
1735 if (TNY_IS_FOLDER (parent)) {
1736 /* Check folder rules */
1737 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1738 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1739 /* Set status failed and set an error */
1740 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1741 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1742 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1743 _("mail_in_ui_folder_create_error"));
1747 if (!strcmp (name, " ") || strchr (name, '/')) {
1748 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1749 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1750 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1751 _("mail_in_ui_folder_create_error"));
1755 CreateFolderInfo *info;
1757 info = g_slice_new0 (CreateFolderInfo);
1758 info->mail_op = g_object_ref (self);
1759 info->callback = callback;
1760 info->user_data = user_data;
1762 modest_mail_operation_notify_start (self);
1764 /* Create the folder */
1765 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1768 /* Call the user callback anyway */
1770 callback (self, parent, NULL, user_data);
1771 /* Notify about operation end */
1772 modest_mail_operation_notify_end (self);
1777 modest_mail_operation_remove_folder (ModestMailOperation *self,
1779 gboolean remove_to_trash)
1781 ModestMailOperationPrivate *priv;
1782 ModestTnyFolderRules rules;
1784 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1785 g_return_if_fail (TNY_IS_FOLDER (folder));
1787 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1789 /* Check folder rules */
1790 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1791 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1792 /* Set status failed and set an error */
1793 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1794 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1795 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1796 _("mail_in_ui_folder_delete_error"));
1800 /* Get the account */
1801 priv->account = modest_tny_folder_get_account (folder);
1802 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1804 /* Delete folder or move to trash */
1805 if (remove_to_trash) {
1806 TnyFolder *trash_folder = NULL;
1807 trash_folder = modest_tny_account_get_special_folder (priv->account,
1808 TNY_FOLDER_TYPE_TRASH);
1809 /* TODO: error_handling */
1811 modest_mail_operation_notify_start (self);
1812 modest_mail_operation_xfer_folder (self, folder,
1813 TNY_FOLDER_STORE (trash_folder),
1815 g_object_unref (trash_folder);
1817 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1820 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1822 modest_mail_operation_notify_start (self);
1823 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1824 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1827 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1829 g_object_unref (parent);
1831 g_warning ("%s: could not get parent folder", __FUNCTION__);
1835 /* Notify about operation end */
1836 modest_mail_operation_notify_end (self);
1840 transfer_folder_status_cb (GObject *obj,
1844 ModestMailOperation *self;
1845 ModestMailOperationPrivate *priv;
1846 ModestMailOperationState *state;
1847 XFerFolderAsyncHelper *helper;
1849 g_return_if_fail (status != NULL);
1851 /* Show only the status information we want */
1852 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1855 helper = (XFerFolderAsyncHelper *) user_data;
1856 g_return_if_fail (helper != NULL);
1858 self = helper->mail_op;
1859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1861 priv->done = status->position;
1862 priv->total = status->of_total;
1864 state = modest_mail_operation_clone_state (self);
1866 /* This is not a GDK lock because we are a Tinymail callback
1867 * which is already GDK locked by Tinymail */
1869 /* no gdk_threads_enter (), CHECKED */
1871 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1873 /* no gdk_threads_leave (), CHECKED */
1875 g_slice_free (ModestMailOperationState, state);
1880 transfer_folder_cb (TnyFolder *folder,
1882 TnyFolderStore *into,
1883 TnyFolder *new_folder,
1887 XFerFolderAsyncHelper *helper;
1888 ModestMailOperation *self = NULL;
1889 ModestMailOperationPrivate *priv = NULL;
1891 helper = (XFerFolderAsyncHelper *) user_data;
1892 g_return_if_fail (helper != NULL);
1894 self = helper->mail_op;
1895 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1898 priv->error = g_error_copy (err);
1900 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1901 } else if (cancelled) {
1902 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1903 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1904 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1905 _("Transference of %s was cancelled."),
1906 tny_folder_get_name (folder));
1909 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1912 /* Notify about operation end */
1913 modest_mail_operation_notify_end (self);
1915 /* If user defined callback function was defined, call it */
1916 if (helper->user_callback) {
1918 /* This is not a GDK lock because we are a Tinymail callback
1919 * which is already GDK locked by Tinymail */
1921 /* no gdk_threads_enter (), CHECKED */
1922 helper->user_callback (self, new_folder, helper->user_data);
1923 /* no gdk_threads_leave () , CHECKED */
1927 g_object_unref (helper->mail_op);
1928 g_slice_free (XFerFolderAsyncHelper, helper);
1933 * This function checks if the new name is a valid name for our local
1934 * folders account. The new name could not be the same than then name
1935 * of any of the mandatory local folders
1937 * We can not rely on tinymail because tinymail does not check the
1938 * name of the virtual folders that the account could have in the case
1939 * that we're doing a rename (because it directly calls Camel which
1940 * knows nothing about our virtual folders).
1942 * In the case of an actual copy/move (i.e. move/copy a folder between
1943 * accounts) tinymail uses the tny_folder_store_create_account which
1944 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1945 * checks the new name of the folder, so this call in that case
1946 * wouldn't be needed. *But* NOTE that if tinymail changes its
1947 * implementation (if folder transfers within the same account is no
1948 * longer implemented as a rename) this call will allow Modest to work
1951 * If the new name is not valid, this function will set the status to
1952 * failed and will set also an error in the mail operation
1955 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1956 TnyFolderStore *into,
1957 const gchar *new_name)
1959 if (TNY_IS_ACCOUNT (into) &&
1960 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1961 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1963 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1964 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1965 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1966 _CS("ckdg_ib_folder_already_exists"));
1973 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1975 TnyFolderStore *parent,
1976 gboolean delete_original,
1977 XferFolderAsyncUserCallback user_callback,
1980 ModestMailOperationPrivate *priv = NULL;
1981 ModestTnyFolderRules parent_rules = 0, rules;
1982 XFerFolderAsyncHelper *helper = NULL;
1983 const gchar *folder_name = NULL;
1984 const gchar *error_msg;
1986 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1987 g_return_if_fail (TNY_IS_FOLDER (folder));
1988 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1991 folder_name = tny_folder_get_name (folder);
1993 /* Set the error msg */
1994 error_msg = _("mail_in_ui_folder_move_target_error");
1996 /* Get account and set it into mail_operation */
1997 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1998 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2001 /* Get folder rules */
2002 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2003 if (TNY_IS_FOLDER (parent))
2004 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2006 /* Apply operation constraints */
2007 if ((gpointer) parent == (gpointer) folder ||
2008 (!TNY_IS_FOLDER_STORE (parent)) ||
2009 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2012 } else if (TNY_IS_FOLDER (parent) &&
2013 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2017 } else if (TNY_IS_FOLDER (parent) &&
2018 TNY_IS_FOLDER_STORE (folder) &&
2019 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2020 TNY_FOLDER_STORE (folder))) {
2021 /* Do not move a parent into a child */
2023 } else if (TNY_IS_FOLDER_STORE (parent) &&
2024 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2025 /* Check that the new folder name is not used by any
2028 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2029 /* Check that the new folder name is not used by any
2030 special local folder */
2033 /* Create the helper */
2034 helper = g_slice_new0 (XFerFolderAsyncHelper);
2035 helper->mail_op = g_object_ref (self);
2036 helper->user_callback = user_callback;
2037 helper->user_data = user_data;
2039 /* Move/Copy folder */
2040 modest_mail_operation_notify_start (self);
2041 tny_folder_copy_async (folder,
2043 tny_folder_get_name (folder),
2046 transfer_folder_status_cb,
2052 /* Set status failed and set an error */
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2058 /* Call the user callback if exists */
2060 user_callback (self, NULL, user_data);
2062 /* Notify the queue */
2063 modest_mail_operation_notify_end (self);
2067 modest_mail_operation_rename_folder (ModestMailOperation *self,
2070 XferFolderAsyncUserCallback user_callback,
2073 ModestMailOperationPrivate *priv;
2074 ModestTnyFolderRules rules;
2075 XFerFolderAsyncHelper *helper;
2077 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2078 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2079 g_return_if_fail (name);
2081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2083 /* Get account and set it into mail_operation */
2084 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2085 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2087 /* Check folder rules */
2088 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2089 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2091 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2094 TnyFolderStore *into;
2096 into = tny_folder_get_folder_store (folder);
2098 /* Check that the new folder name is not used by any
2099 special local folder */
2100 if (new_name_valid_if_local_account (priv, into, name)) {
2101 /* Create the helper */
2102 helper = g_slice_new0 (XFerFolderAsyncHelper);
2103 helper->mail_op = g_object_ref(self);
2104 helper->user_callback = user_callback;
2105 helper->user_data = user_data;
2107 /* Rename. Camel handles folder subscription/unsubscription */
2108 modest_mail_operation_notify_start (self);
2109 tny_folder_copy_async (folder, into, name, TRUE,
2111 transfer_folder_status_cb,
2116 g_object_unref (into);
2121 /* Set status failed and set an error */
2122 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2123 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2124 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2125 _("FIXME: unable to rename"));
2128 user_callback (self, NULL, user_data);
2130 /* Notify about operation end */
2131 modest_mail_operation_notify_end (self);
2134 /* ******************************************************************* */
2135 /* ************************** MSG ACTIONS ************************* */
2136 /* ******************************************************************* */
2139 modest_mail_operation_get_msg (ModestMailOperation *self,
2141 GetMsgAsyncUserCallback user_callback,
2144 GetMsgInfo *helper = NULL;
2146 ModestMailOperationPrivate *priv;
2148 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2149 g_return_if_fail (TNY_IS_HEADER (header));
2151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2152 folder = tny_header_get_folder (header);
2154 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2158 /* Get account and set it into mail_operation */
2159 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2161 /* Check for cached messages */
2162 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2163 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2165 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2167 /* Create the helper */
2168 helper = g_slice_new0 (GetMsgInfo);
2169 helper->header = g_object_ref (header);
2170 helper->mail_op = g_object_ref (self);
2171 helper->user_callback = user_callback;
2172 helper->user_data = user_data;
2173 helper->destroy_notify = NULL;
2174 helper->last_total_bytes = 0;
2175 helper->sum_total_bytes = 0;
2176 helper->total_bytes = tny_header_get_message_size (header);
2178 modest_mail_operation_notify_start (self);
2180 /* notify about the start of the operation */
2181 ModestMailOperationState *state;
2182 state = modest_mail_operation_clone_state (self);
2185 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2188 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2190 g_object_unref (G_OBJECT (folder));
2194 get_msg_status_cb (GObject *obj,
2198 GetMsgInfo *helper = NULL;
2200 g_return_if_fail (status != NULL);
2202 /* Show only the status information we want */
2203 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2206 helper = (GetMsgInfo *) user_data;
2207 g_return_if_fail (helper != NULL);
2209 /* Notify progress */
2210 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2211 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2215 get_msg_async_cb (TnyFolder *folder,
2221 GetMsgInfo *info = NULL;
2222 ModestMailOperationPrivate *priv = NULL;
2225 info = (GetMsgInfo *) user_data;
2227 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2230 if (info->more_msgs) {
2231 tny_iterator_next (info->more_msgs);
2232 finished = (tny_iterator_is_done (info->more_msgs));
2234 finished = (priv->done == priv->total) ? TRUE : FALSE;
2237 /* If canceled by the user, ignore the error given by Tinymail */
2238 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2242 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2244 priv->error = g_error_copy ((const GError *) err);
2245 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2248 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2249 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2252 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2253 /* Set the success status before calling the user callback */
2254 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2258 /* Call the user callback */
2259 if (info->user_callback)
2260 info->user_callback (info->mail_op, info->header, canceled,
2261 msg, err, info->user_data);
2263 /* Notify about operation end if this is the last callback */
2265 /* Free user data */
2266 if (info->destroy_notify)
2267 info->destroy_notify (info->user_data);
2269 /* Notify about operation end */
2270 modest_mail_operation_notify_end (info->mail_op);
2273 if (info->more_msgs)
2274 g_object_unref (info->more_msgs);
2275 g_object_unref (info->header);
2276 g_object_unref (info->mail_op);
2277 g_slice_free (GetMsgInfo, info);
2278 } else if (info->more_msgs) {
2279 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2280 TnyFolder *folder = tny_header_get_folder (header);
2282 g_object_unref (info->header);
2283 info->header = g_object_ref (header);
2285 /* Retrieve the next message */
2286 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2288 g_object_unref (header);
2289 g_object_unref (folder);
2291 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2296 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2297 TnyList *header_list,
2298 GetMsgAsyncUserCallback user_callback,
2300 GDestroyNotify notify)
2302 ModestMailOperationPrivate *priv = NULL;
2304 TnyIterator *iter = NULL;
2305 gboolean has_uncached_messages;
2307 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2309 /* Init mail operation */
2310 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2311 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2313 priv->total = tny_list_get_length(header_list);
2315 /* Check uncached messages */
2316 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2317 !has_uncached_messages && !tny_iterator_is_done (iter);
2318 tny_iterator_next (iter)) {
2321 header = (TnyHeader *) tny_iterator_get_current (iter);
2322 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2323 has_uncached_messages = TRUE;
2324 g_object_unref (header);
2326 g_object_unref (iter);
2327 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2329 /* Get account and set it into mail_operation */
2330 if (tny_list_get_length (header_list) >= 1) {
2331 TnyIterator *iterator = tny_list_create_iterator (header_list);
2332 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2334 TnyFolder *folder = tny_header_get_folder (header);
2336 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2337 g_object_unref (folder);
2339 g_object_unref (header);
2341 g_object_unref (iterator);
2344 msg_list_size = compute_message_list_size (header_list);
2346 modest_mail_operation_notify_start (self);
2347 iter = tny_list_create_iterator (header_list);
2348 if (!tny_iterator_is_done (iter)) {
2349 /* notify about the start of the operation */
2350 ModestMailOperationState *state;
2351 state = modest_mail_operation_clone_state (self);
2354 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2357 GetMsgInfo *msg_info = NULL;
2358 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2359 TnyFolder *folder = tny_header_get_folder (header);
2361 /* Create the message info */
2362 msg_info = g_slice_new0 (GetMsgInfo);
2363 msg_info->mail_op = g_object_ref (self);
2364 msg_info->header = g_object_ref (header);
2365 msg_info->more_msgs = g_object_ref (iter);
2366 msg_info->user_callback = user_callback;
2367 msg_info->user_data = user_data;
2368 msg_info->destroy_notify = notify;
2369 msg_info->last_total_bytes = 0;
2370 msg_info->sum_total_bytes = 0;
2371 msg_info->total_bytes = msg_list_size;
2373 /* The callback will call it per each header */
2374 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2376 /* Free and go on */
2377 g_object_unref (header);
2378 g_object_unref (folder);
2379 g_slice_free (ModestMailOperationState, state);
2381 g_object_unref (iter);
2386 remove_msgs_async_cb (TnyFolder *folder,
2391 gboolean expunge, leave_on_server;
2392 const gchar *account_name;
2394 TnyAccount *account;
2395 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2396 ModestMailOperation *self;
2397 ModestMailOperationPrivate *priv;
2399 self = (ModestMailOperation *) user_data;
2400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2402 if (canceled || err) {
2403 /* If canceled by the user, ignore the error given by Tinymail */
2405 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2407 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2408 priv->error = g_error_copy ((const GError *) err);
2409 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2412 modest_mail_operation_notify_end (self);
2413 g_object_unref (self);
2417 account = tny_folder_get_account (folder);
2418 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2420 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2422 proto = tny_account_get_proto (account);
2423 g_object_unref (account);
2426 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2428 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2429 modest_tny_folder_is_remote_folder (folder) == FALSE)
2435 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2440 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2442 gboolean remove_to_trash /*ignored*/)
2444 TnyFolder *folder = NULL;
2445 ModestMailOperationPrivate *priv;
2446 TnyIterator *iter = NULL;
2447 TnyHeader *header = NULL;
2448 TnyList *remove_headers = NULL;
2449 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2451 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2452 g_return_if_fail (TNY_IS_LIST (headers));
2454 if (remove_to_trash)
2455 g_warning ("remove to trash is not implemented");
2457 if (tny_list_get_length(headers) == 0) {
2458 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2459 goto cleanup; /* nothing to do */
2462 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2463 remove_headers = g_object_ref(headers);
2465 /* Get folder from first header and sync it */
2466 iter = tny_list_create_iterator (headers);
2467 header = TNY_HEADER (tny_iterator_get_current (iter));
2469 folder = tny_header_get_folder (header);
2470 if (!TNY_IS_FOLDER(folder)) {
2471 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2475 /* Don't remove messages that are being sent */
2476 if (modest_tny_folder_is_local_folder (folder)) {
2477 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2479 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2480 TnyTransportAccount *traccount = NULL;
2481 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2482 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2484 ModestTnySendQueueStatus status;
2485 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2486 TnyIterator *iter = tny_list_create_iterator(headers);
2487 g_object_unref(remove_headers);
2488 remove_headers = TNY_LIST(tny_simple_list_new());
2489 while (!tny_iterator_is_done(iter)) {
2491 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2492 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2493 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2494 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2495 tny_list_append(remove_headers, G_OBJECT(hdr));
2497 g_object_unref(hdr);
2499 tny_iterator_next(iter);
2501 g_object_unref(iter);
2502 g_object_unref(traccount);
2506 /* Get account and set it into mail_operation */
2507 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2508 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2509 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2511 /* remove message from folder */
2512 modest_mail_operation_notify_start (self);
2513 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2514 NULL, g_object_ref (self));
2518 g_object_unref (remove_headers);
2520 g_object_unref (header);
2522 g_object_unref (iter);
2524 g_object_unref (folder);
2528 notify_progress_of_multiple_messages (ModestMailOperation *self,
2530 gint *last_total_bytes,
2531 gint *sum_total_bytes,
2533 gboolean increment_done)
2535 ModestMailOperationPrivate *priv;
2536 ModestMailOperationState *state;
2537 gboolean is_num_bytes = FALSE;
2539 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2541 /* We know that tinymail sends us information about
2542 * transferred bytes with this particular message
2544 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2545 * I just added the 'if' so we don't get runtime warning)
2547 if (status->message)
2548 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2550 state = modest_mail_operation_clone_state (self);
2551 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2552 /* We know that we're in a different message when the
2553 total number of bytes to transfer is different. Of
2554 course it could fail if we're transferring messages
2555 of the same size, but this is a workarround */
2556 if (status->of_total != *last_total_bytes) {
2557 /* We need to increment the done when there is
2558 no information about each individual
2559 message, we need to do this in message
2560 transfers, and we don't do it for getting
2564 *sum_total_bytes += *last_total_bytes;
2565 *last_total_bytes = status->of_total;
2567 state->bytes_done += status->position + *sum_total_bytes;
2568 state->bytes_total = total_bytes;
2570 /* Notify the status change. Only notify about changes
2571 referred to bytes */
2572 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2576 g_slice_free (ModestMailOperationState, state);
2580 transfer_msgs_status_cb (GObject *obj,
2584 XFerMsgsAsyncHelper *helper;
2586 g_return_if_fail (status != NULL);
2588 /* Show only the status information we want */
2589 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2592 helper = (XFerMsgsAsyncHelper *) user_data;
2593 g_return_if_fail (helper != NULL);
2595 /* Notify progress */
2596 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2597 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2602 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2604 XFerMsgsAsyncHelper *helper;
2605 ModestMailOperation *self;
2606 ModestMailOperationPrivate *priv;
2607 gboolean finished = TRUE;
2609 helper = (XFerMsgsAsyncHelper *) user_data;
2610 self = helper->mail_op;
2612 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2615 priv->error = g_error_copy (err);
2617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2618 } else if (cancelled) {
2619 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2620 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2621 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2622 _("Error trying to refresh the contents of %s"),
2623 tny_folder_get_name (folder));
2624 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2625 if (helper->more_msgs) {
2626 /* We'll transfer the next message in the list */
2627 tny_iterator_next (helper->more_msgs);
2628 if (!tny_iterator_is_done (helper->more_msgs)) {
2629 GObject *next_header;
2630 g_object_unref (helper->headers);
2631 helper->headers = tny_simple_list_new ();
2632 next_header = tny_iterator_get_current (helper->more_msgs);
2633 tny_list_append (helper->headers, next_header);
2634 g_object_unref (next_header);
2641 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2647 /* Update folder counts */
2648 tny_folder_poke_status (folder);
2649 tny_folder_poke_status (helper->dest_folder);
2651 /* Notify about operation end */
2652 modest_mail_operation_notify_end (self);
2654 /* If user defined callback function was defined, call it */
2655 if (helper->user_callback) {
2656 /* This is not a GDK lock because we are a Tinymail callback and
2657 * Tinymail already acquires the Gdk lock */
2659 /* no gdk_threads_enter (), CHECKED */
2660 helper->user_callback (self, helper->user_data);
2661 /* no gdk_threads_leave (), CHECKED */
2665 if (helper->more_msgs)
2666 g_object_unref (helper->more_msgs);
2667 if (helper->headers)
2668 g_object_unref (helper->headers);
2669 if (helper->dest_folder)
2670 g_object_unref (helper->dest_folder);
2671 if (helper->mail_op)
2672 g_object_unref (helper->mail_op);
2673 g_slice_free (XFerMsgsAsyncHelper, helper);
2675 /* Transfer more messages */
2676 tny_folder_transfer_msgs_async (folder,
2678 helper->dest_folder,
2681 transfer_msgs_status_cb,
2687 compute_message_list_size (TnyList *headers)
2692 iter = tny_list_create_iterator (headers);
2693 while (!tny_iterator_is_done (iter)) {
2694 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2695 size += tny_header_get_message_size (header);
2696 g_object_unref (header);
2697 tny_iterator_next (iter);
2699 g_object_unref (iter);
2705 compute_message_array_size (GPtrArray *headers)
2710 for (i = 0; i < headers->len; i++) {
2711 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2712 size += tny_header_get_message_size (header);
2720 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2723 gboolean delete_original,
2724 XferMsgsAsyncUserCallback user_callback,
2727 ModestMailOperationPrivate *priv = NULL;
2728 TnyIterator *iter = NULL;
2729 TnyFolder *src_folder = NULL;
2730 XFerMsgsAsyncHelper *helper = NULL;
2731 TnyHeader *header = NULL;
2732 ModestTnyFolderRules rules = 0;
2733 TnyAccount *dst_account = NULL;
2734 gboolean leave_on_server;
2736 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2737 g_return_if_fail (headers && TNY_IS_LIST (headers));
2738 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2740 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2741 priv->total = tny_list_get_length (headers);
2743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2744 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2746 /* Apply folder rules */
2747 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2748 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2749 /* Set status failed and set an error */
2750 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2751 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2752 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2753 _CS("ckct_ib_unable_to_paste_here"));
2754 /* Notify the queue */
2755 modest_mail_operation_notify_end (self);
2759 /* Get source folder */
2760 iter = tny_list_create_iterator (headers);
2761 header = TNY_HEADER (tny_iterator_get_current (iter));
2763 src_folder = tny_header_get_folder (header);
2764 g_object_unref (header);
2766 g_object_unref (iter);
2768 if (src_folder == NULL) {
2769 /* Notify the queue */
2770 modest_mail_operation_notify_end (self);
2772 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2777 /* Check folder source and destination */
2778 if (src_folder == folder) {
2779 /* Set status failed and set an error */
2780 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2781 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2782 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2783 _("mail_in_ui_folder_copy_target_error"));
2785 /* Notify the queue */
2786 modest_mail_operation_notify_end (self);
2789 g_object_unref (src_folder);
2793 /* Create the helper */
2794 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2795 helper->mail_op = g_object_ref(self);
2796 helper->dest_folder = g_object_ref(folder);
2797 helper->user_callback = user_callback;
2798 helper->user_data = user_data;
2799 helper->delete = delete_original;
2800 helper->last_total_bytes = 0;
2801 helper->sum_total_bytes = 0;
2802 helper->total_bytes = compute_message_list_size (headers);
2804 /* Get account and set it into mail_operation */
2805 priv->account = modest_tny_folder_get_account (src_folder);
2806 dst_account = modest_tny_folder_get_account (folder);
2808 if (priv->account == dst_account) {
2809 /* Transfer all messages at once using the fast
2810 * method. Note that depending on the server this
2811 * might not be that fast, and might not be
2812 * user-cancellable either */
2813 helper->headers = g_object_ref (headers);
2814 helper->more_msgs = NULL;
2816 /* Transfer messages one by one so the user can cancel
2819 helper->headers = tny_simple_list_new ();
2820 helper->more_msgs = tny_list_create_iterator (headers);
2821 hdr = tny_iterator_get_current (helper->more_msgs);
2822 tny_list_append (helper->headers, hdr);
2823 g_object_unref (hdr);
2826 /* If leave_on_server is set to TRUE then don't use
2827 delete_original, we always pass FALSE. This is because
2828 otherwise tinymail will try to sync the source folder and
2829 this could cause an error if we're offline while
2830 transferring an already downloaded message from a POP
2832 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2833 MODEST_PROTOCOL_STORE_POP) {
2834 const gchar *account_name;
2836 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2837 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2840 leave_on_server = FALSE;
2843 modest_mail_operation_notify_start (self);
2844 tny_folder_transfer_msgs_async (src_folder,
2847 (leave_on_server) ? FALSE : delete_original,
2849 transfer_msgs_status_cb,
2851 g_object_unref (src_folder);
2852 g_object_unref (dst_account);
2857 on_refresh_folder (TnyFolder *folder,
2862 RefreshAsyncHelper *helper = NULL;
2863 ModestMailOperation *self = NULL;
2864 ModestMailOperationPrivate *priv = NULL;
2866 helper = (RefreshAsyncHelper *) user_data;
2867 self = helper->mail_op;
2868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2870 g_return_if_fail(priv!=NULL);
2873 priv->error = g_error_copy (error);
2874 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2879 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2880 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2881 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2882 _("Error trying to refresh the contents of %s"),
2883 tny_folder_get_name (folder));
2887 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2890 /* Call user defined callback, if it exists */
2891 if (helper->user_callback) {
2893 /* This is not a GDK lock because we are a Tinymail callback and
2894 * Tinymail already acquires the Gdk lock */
2895 helper->user_callback (self, folder, helper->user_data);
2899 g_slice_free (RefreshAsyncHelper, helper);
2901 /* Notify about operation end */
2902 modest_mail_operation_notify_end (self);
2903 g_object_unref(self);
2907 on_refresh_folder_status_update (GObject *obj,
2911 RefreshAsyncHelper *helper = NULL;
2912 ModestMailOperation *self = NULL;
2913 ModestMailOperationPrivate *priv = NULL;
2914 ModestMailOperationState *state;
2916 g_return_if_fail (user_data != NULL);
2917 g_return_if_fail (status != NULL);
2919 /* Show only the status information we want */
2920 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2923 helper = (RefreshAsyncHelper *) user_data;
2924 self = helper->mail_op;
2925 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2927 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2929 priv->done = status->position;
2930 priv->total = status->of_total;
2932 state = modest_mail_operation_clone_state (self);
2934 /* This is not a GDK lock because we are a Tinymail callback and
2935 * Tinymail already acquires the Gdk lock */
2936 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2938 g_slice_free (ModestMailOperationState, state);
2942 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2944 RefreshAsyncUserCallback user_callback,
2947 ModestMailOperationPrivate *priv = NULL;
2948 RefreshAsyncHelper *helper = NULL;
2950 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2952 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2954 /* Get account and set it into mail_operation */
2955 priv->account = modest_tny_folder_get_account (folder);
2956 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2958 /* Create the helper */
2959 helper = g_slice_new0 (RefreshAsyncHelper);
2960 helper->mail_op = g_object_ref(self);
2961 helper->user_callback = user_callback;
2962 helper->user_data = user_data;
2964 modest_mail_operation_notify_start (self);
2966 /* notify that the operation was started */
2967 ModestMailOperationState *state;
2968 state = modest_mail_operation_clone_state (self);
2971 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2974 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2976 tny_folder_refresh_async (folder,
2978 on_refresh_folder_status_update,
2983 run_queue_stop (ModestTnySendQueue *queue,
2984 ModestMailOperation *self)
2986 ModestMailOperationPrivate *priv;
2988 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2989 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2992 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2994 modest_mail_operation_notify_end (self);
2995 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
2996 g_object_unref (self);
2999 modest_mail_operation_run_queue (ModestMailOperation *self,
3000 ModestTnySendQueue *queue)
3002 ModestMailOperationPrivate *priv;
3004 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3005 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3006 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3008 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3009 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3010 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3012 modest_mail_operation_notify_start (self);
3013 g_object_ref (self);
3014 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3018 sync_folder_finish_callback (TnyFolder *self,
3024 ModestMailOperation *mail_op;
3025 ModestMailOperationPrivate *priv;
3027 mail_op = (ModestMailOperation *) user_data;
3028 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3030 /* If canceled by the user, ignore the error given by Tinymail */
3032 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3034 /* If the operation was a sync then the status is
3035 failed, but if it's part of another operation then
3036 just set it as finished with errors */
3037 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3038 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3040 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3041 priv->error = g_error_copy ((const GError *) err);
3042 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3044 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3047 modest_mail_operation_notify_end (mail_op);
3048 g_object_unref (mail_op);
3052 modest_mail_operation_sync_folder (ModestMailOperation *self,
3053 TnyFolder *folder, gboolean expunge)
3055 ModestMailOperationPrivate *priv;
3057 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3058 g_return_if_fail (TNY_IS_FOLDER (folder));
3059 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3061 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3062 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3063 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3065 modest_mail_operation_notify_start (self);
3066 g_object_ref (self);
3067 tny_folder_sync_async (folder, expunge,
3068 (TnyFolderCallback) sync_folder_finish_callback,
3073 modest_mail_operation_notify_start (ModestMailOperation *self)
3075 ModestMailOperationPrivate *priv = NULL;
3077 g_return_if_fail (self);
3079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3081 /* Ensure that all the fields are filled correctly */
3082 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3084 /* Notify the observers about the mail operation. We do not
3085 wrapp this emission because we assume that this function is
3086 always called from within the main lock */
3087 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3092 * It's used by the mail operation queue to notify the observers
3093 * attached to that signal that the operation finished. We need to use
3094 * that because tinymail does not give us the progress of a given
3095 * operation when it finishes (it directly calls the operation
3099 modest_mail_operation_notify_end (ModestMailOperation *self)
3101 ModestMailOperationPrivate *priv = NULL;
3103 g_return_if_fail (self);
3105 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3107 /* Notify the observers about the mail operation end. We do
3108 not wrapp this emission because we assume that this
3109 function is always called from within the main lock */
3110 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3112 /* Remove the error user data */
3113 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3114 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3118 modest_mail_operation_get_account (ModestMailOperation *self)
3120 ModestMailOperationPrivate *priv = NULL;
3122 g_return_val_if_fail (self, NULL);
3124 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3126 return (priv->account) ? g_object_ref (priv->account) : NULL;
3130 modest_mail_operation_noop (ModestMailOperation *self)
3132 ModestMailOperationPrivate *priv = NULL;
3134 g_return_if_fail (self);
3136 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3137 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3138 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3142 /* This mail operation does nothing actually */
3143 modest_mail_operation_notify_start (self);
3144 modest_mail_operation_notify_end (self);
3149 modest_mail_operation_to_string (ModestMailOperation *self)
3151 const gchar *type, *status, *account_id;
3152 ModestMailOperationPrivate *priv = NULL;
3154 g_return_val_if_fail (self, NULL);
3156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3158 /* new operations don't have anything interesting */
3159 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3160 return g_strdup_printf ("%p <new operation>", self);
3162 switch (priv->op_type) {
3163 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3164 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3165 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3166 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3167 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3168 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3169 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3170 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3171 default: type = "UNEXPECTED"; break;
3174 switch (priv->status) {
3175 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3176 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3177 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3178 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3179 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3180 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3181 default: status= "UNEXPECTED"; break;
3184 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3186 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3187 priv->done, priv->total,
3188 priv->error && priv->error->message ? priv->error->message : "");