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, succeeded;
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));
1309 if (!canceled && !err)
1310 modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
1312 if (new_headers_array->len == 0)
1315 /* Get per-account message amount retrieval limit */
1316 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1317 if (retrieve_limit == 0)
1318 retrieve_limit = G_MAXINT;
1320 /* Get per-account retrieval type */
1321 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1322 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1325 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1327 /* Ask the users if they want to retrieve all the messages
1328 even though the limit was exceeded */
1329 ignore_limit = FALSE;
1330 if (new_headers_array->len > retrieve_limit) {
1331 /* Ask the user if a callback has been specified and
1332 if the mail operation has a source (this means that
1333 was invoked by the user and not automatically by a
1335 if (info->retrieve_all_cb && priv->source)
1336 ignore_limit = info->retrieve_all_cb (priv->source,
1337 new_headers_array->len,
1341 if (!headers_only) {
1343 const gint msg_list_size = compute_message_array_size (new_headers_array);
1347 priv->total = new_headers_array->len;
1349 priv->total = MIN (new_headers_array->len, retrieve_limit);
1350 while (msg_num < priv->total) {
1351 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1352 TnyFolder *folder = tny_header_get_folder (header);
1353 GetMsgInfo *msg_info;
1355 /* Create the message info */
1356 msg_info = g_slice_new0 (GetMsgInfo);
1357 msg_info->mail_op = g_object_ref (info->mail_op);
1358 msg_info->header = g_object_ref (header);
1359 msg_info->total_bytes = msg_list_size;
1361 /* Get message in an async way */
1362 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1363 get_msg_status_cb, msg_info);
1365 g_object_unref (folder);
1371 /* Copy the headers to a list and free the array */
1372 new_headers = tny_simple_list_new ();
1373 for (i=0; i < new_headers_array->len; i++) {
1374 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1375 tny_list_append (new_headers, G_OBJECT (header));
1377 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1378 g_ptr_array_free (new_headers_array, FALSE);
1384 modest_account_mgr_set_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1385 tny_account_get_name (priv->account),
1388 /* Get the transport account */
1389 transport_account = (TnyTransportAccount *)
1390 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1391 info->account_name);
1393 if (transport_account) {
1394 ModestTnySendQueue *send_queue;
1398 send_queue = modest_runtime_get_send_queue (transport_account);
1399 g_object_unref (transport_account);
1401 /* Get outbox folder */
1402 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1403 if (outbox) { /* this could fail in some cases */
1404 num_messages = tny_folder_get_all_count (outbox);
1405 g_object_unref (outbox);
1407 g_warning ("%s: could not get outbox", __FUNCTION__);
1411 if (num_messages != 0) {
1412 /* Reenable suspended items */
1413 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1416 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1417 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1422 /* Check if the operation was a success */
1424 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1426 /* Call the user callback and free */
1427 update_account_notify_user_and_free (info, new_headers);
1431 recurse_folders_async_cb (TnyFolderStore *folder_store,
1437 UpdateAccountInfo *info;
1438 ModestMailOperationPrivate *priv;
1440 info = (UpdateAccountInfo *) user_data;
1441 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1443 if (err || canceled) {
1444 /* If the error was previosly set by another callback
1445 don't set it again */
1447 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1449 priv->error = g_error_copy (err);
1451 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1452 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1456 /* We're not getting INBOX children if we don't want to poke all */
1457 TnyIterator *iter = tny_list_create_iterator (list);
1458 while (!tny_iterator_is_done (iter)) {
1459 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1461 /* Add to the list of all folders */
1462 tny_list_append (info->folders, (GObject *) folder);
1464 if (info->poke_all) {
1465 TnyList *folders = tny_simple_list_new ();
1466 /* Add pending call */
1467 info->pending_calls++;
1469 tny_folder_store_get_folders_async (folder, folders, NULL,
1470 recurse_folders_async_cb,
1472 g_object_unref (folders);
1475 g_object_unref (G_OBJECT (folder));
1477 tny_iterator_next (iter);
1479 g_object_unref (G_OBJECT (iter));
1482 /* Remove my own pending call */
1483 info->pending_calls--;
1485 /* This means that we have all the folders */
1486 if (info->pending_calls == 0) {
1487 TnyIterator *iter_all_folders;
1488 TnyFolder *inbox = NULL;
1490 /* If there was any error do not continue */
1492 update_account_notify_user_and_free (info, NULL);
1496 iter_all_folders = tny_list_create_iterator (info->folders);
1498 /* Do a poke status over all folders */
1499 while (!tny_iterator_is_done (iter_all_folders) &&
1500 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1501 TnyFolder *folder = NULL;
1503 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1505 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1506 /* Get a reference to the INBOX */
1507 inbox = g_object_ref (folder);
1509 /* Issue a poke status over the folder */
1511 tny_folder_poke_status (folder);
1514 /* Free and go to next */
1515 g_object_unref (folder);
1516 tny_iterator_next (iter_all_folders);
1518 g_object_unref (iter_all_folders);
1520 /* Refresh the INBOX */
1522 /* Refresh the folder. Our observer receives
1523 * the new emails during folder refreshes, so
1524 * we can use observer->new_headers
1526 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1527 tny_folder_add_observer (inbox, info->inbox_observer);
1529 /* Refresh the INBOX */
1530 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1531 g_object_unref (inbox);
1533 /* We could not perform the inbox refresh but
1534 we'll try to send mails anyway */
1535 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1541 modest_mail_operation_update_account (ModestMailOperation *self,
1542 const gchar *account_name,
1544 gboolean interactive,
1545 RetrieveAllCallback retrieve_all_cb,
1546 UpdateAccountCallback callback,
1549 UpdateAccountInfo *info = NULL;
1550 ModestMailOperationPrivate *priv = NULL;
1551 ModestTnyAccountStore *account_store = NULL;
1553 ModestMailOperationState *state;
1555 /* Init mail operation */
1556 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1559 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1560 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1562 /* Get the store account */
1563 account_store = modest_runtime_get_account_store ();
1565 modest_tny_account_store_get_server_account (account_store,
1567 TNY_ACCOUNT_TYPE_STORE);
1569 /* The above function could return NULL */
1570 if (!priv->account) {
1571 /* Check if the operation was a success */
1572 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1573 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1575 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1577 /* Call the user callback */
1579 callback (self, NULL, user_data);
1581 /* Notify about operation end */
1582 modest_mail_operation_notify_end (self);
1587 /* We have once seen priv->account getting finalized during this code,
1588 * therefore adding a reference (bug #82296) */
1590 g_object_ref (priv->account);
1592 /* Create the helper object */
1593 info = g_slice_new0 (UpdateAccountInfo);
1594 info->pending_calls = 1;
1595 info->folders = tny_simple_list_new ();
1596 info->mail_op = g_object_ref (self);
1597 info->poke_all = poke_all;
1598 info->interactive = interactive;
1599 info->account_name = g_strdup (account_name);
1600 info->callback = callback;
1601 info->user_data = user_data;
1602 info->retrieve_all_cb = retrieve_all_cb;
1604 /* Set account busy */
1605 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1606 modest_mail_operation_notify_start (self);
1608 /* notify about the start of the operation */
1609 state = modest_mail_operation_clone_state (self);
1613 /* Start notifying progress */
1614 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1615 g_slice_free (ModestMailOperationState, state);
1617 /* Get all folders and continue in the callback */
1618 folders = tny_simple_list_new ();
1619 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1621 recurse_folders_async_cb,
1623 g_object_unref (folders);
1625 g_object_unref (priv->account);
1630 * Used to notify the queue from the main
1631 * loop. We call it inside an idle call to achieve that
1634 idle_notify_queue (gpointer data)
1636 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1638 gdk_threads_enter ();
1639 modest_mail_operation_notify_end (mail_op);
1640 gdk_threads_leave ();
1641 g_object_unref (mail_op);
1647 compare_headers_by_date (gconstpointer a,
1650 TnyHeader **header1, **header2;
1651 time_t sent1, sent2;
1653 header1 = (TnyHeader **) a;
1654 header2 = (TnyHeader **) b;
1656 sent1 = tny_header_get_date_sent (*header1);
1657 sent2 = tny_header_get_date_sent (*header2);
1659 /* We want the most recent ones (greater time_t) at the
1668 /* ******************************************************************* */
1669 /* ************************** STORE ACTIONS ************************* */
1670 /* ******************************************************************* */
1673 ModestMailOperation *mail_op;
1674 CreateFolderUserCallback callback;
1680 create_folder_cb (TnyFolderStore *parent_folder,
1682 TnyFolder *new_folder,
1686 ModestMailOperationPrivate *priv;
1687 CreateFolderInfo *info;
1689 info = (CreateFolderInfo *) user_data;
1690 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1692 if (canceled || err) {
1693 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1695 priv->error = g_error_copy (err);
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1701 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1704 /* The user will unref the new_folder */
1706 info->callback (info->mail_op, parent_folder,
1707 new_folder, info->user_data);
1709 /* Notify about operation end */
1710 modest_mail_operation_notify_end (info->mail_op);
1713 g_object_unref (info->mail_op);
1714 g_slice_free (CreateFolderInfo, info);
1718 modest_mail_operation_create_folder (ModestMailOperation *self,
1719 TnyFolderStore *parent,
1721 CreateFolderUserCallback callback,
1724 ModestMailOperationPrivate *priv;
1726 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1727 g_return_if_fail (name);
1729 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1730 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1731 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1732 g_object_ref (parent) :
1733 modest_tny_folder_get_account (TNY_FOLDER (parent));
1735 /* Check for already existing folder */
1736 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1737 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1738 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1739 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1740 _CS("ckdg_ib_folder_already_exists"));
1744 if (TNY_IS_FOLDER (parent)) {
1745 /* Check folder rules */
1746 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1747 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1748 /* Set status failed and set an error */
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1750 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1751 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1752 _("mail_in_ui_folder_create_error"));
1756 if (!strcmp (name, " ") || strchr (name, '/')) {
1757 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1758 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1759 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1760 _("mail_in_ui_folder_create_error"));
1764 CreateFolderInfo *info;
1766 info = g_slice_new0 (CreateFolderInfo);
1767 info->mail_op = g_object_ref (self);
1768 info->callback = callback;
1769 info->user_data = user_data;
1771 modest_mail_operation_notify_start (self);
1773 /* Create the folder */
1774 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1777 /* Call the user callback anyway */
1779 callback (self, parent, NULL, user_data);
1780 /* Notify about operation end */
1781 modest_mail_operation_notify_end (self);
1786 modest_mail_operation_remove_folder (ModestMailOperation *self,
1788 gboolean remove_to_trash)
1790 ModestMailOperationPrivate *priv;
1791 ModestTnyFolderRules rules;
1793 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1794 g_return_if_fail (TNY_IS_FOLDER (folder));
1796 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1798 /* Check folder rules */
1799 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1800 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1801 /* Set status failed and set an error */
1802 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1803 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1804 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1805 _("mail_in_ui_folder_delete_error"));
1809 /* Get the account */
1810 priv->account = modest_tny_folder_get_account (folder);
1811 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1813 /* Delete folder or move to trash */
1814 if (remove_to_trash) {
1815 TnyFolder *trash_folder = NULL;
1816 trash_folder = modest_tny_account_get_special_folder (priv->account,
1817 TNY_FOLDER_TYPE_TRASH);
1818 /* TODO: error_handling */
1820 modest_mail_operation_notify_start (self);
1821 modest_mail_operation_xfer_folder (self, folder,
1822 TNY_FOLDER_STORE (trash_folder),
1824 g_object_unref (trash_folder);
1826 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1829 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1831 modest_mail_operation_notify_start (self);
1832 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1833 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1836 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1838 g_object_unref (parent);
1840 g_warning ("%s: could not get parent folder", __FUNCTION__);
1844 /* Notify about operation end */
1845 modest_mail_operation_notify_end (self);
1849 transfer_folder_status_cb (GObject *obj,
1853 ModestMailOperation *self;
1854 ModestMailOperationPrivate *priv;
1855 ModestMailOperationState *state;
1856 XFerFolderAsyncHelper *helper;
1858 g_return_if_fail (status != NULL);
1860 /* Show only the status information we want */
1861 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1864 helper = (XFerFolderAsyncHelper *) user_data;
1865 g_return_if_fail (helper != NULL);
1867 self = helper->mail_op;
1868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1870 priv->done = status->position;
1871 priv->total = status->of_total;
1873 state = modest_mail_operation_clone_state (self);
1875 /* This is not a GDK lock because we are a Tinymail callback
1876 * which is already GDK locked by Tinymail */
1878 /* no gdk_threads_enter (), CHECKED */
1880 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1882 /* no gdk_threads_leave (), CHECKED */
1884 g_slice_free (ModestMailOperationState, state);
1889 transfer_folder_cb (TnyFolder *folder,
1891 TnyFolderStore *into,
1892 TnyFolder *new_folder,
1896 XFerFolderAsyncHelper *helper;
1897 ModestMailOperation *self = NULL;
1898 ModestMailOperationPrivate *priv = NULL;
1900 helper = (XFerFolderAsyncHelper *) user_data;
1901 g_return_if_fail (helper != NULL);
1903 self = helper->mail_op;
1904 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1907 priv->error = g_error_copy (err);
1909 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1910 } else if (cancelled) {
1911 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1912 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1913 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1914 _("Transference of %s was cancelled."),
1915 tny_folder_get_name (folder));
1918 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1921 /* Notify about operation end */
1922 modest_mail_operation_notify_end (self);
1924 /* If user defined callback function was defined, call it */
1925 if (helper->user_callback) {
1927 /* This is not a GDK lock because we are a Tinymail callback
1928 * which is already GDK locked by Tinymail */
1930 /* no gdk_threads_enter (), CHECKED */
1931 helper->user_callback (self, new_folder, helper->user_data);
1932 /* no gdk_threads_leave () , CHECKED */
1936 g_object_unref (helper->mail_op);
1937 g_slice_free (XFerFolderAsyncHelper, helper);
1942 * This function checks if the new name is a valid name for our local
1943 * folders account. The new name could not be the same than then name
1944 * of any of the mandatory local folders
1946 * We can not rely on tinymail because tinymail does not check the
1947 * name of the virtual folders that the account could have in the case
1948 * that we're doing a rename (because it directly calls Camel which
1949 * knows nothing about our virtual folders).
1951 * In the case of an actual copy/move (i.e. move/copy a folder between
1952 * accounts) tinymail uses the tny_folder_store_create_account which
1953 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1954 * checks the new name of the folder, so this call in that case
1955 * wouldn't be needed. *But* NOTE that if tinymail changes its
1956 * implementation (if folder transfers within the same account is no
1957 * longer implemented as a rename) this call will allow Modest to work
1960 * If the new name is not valid, this function will set the status to
1961 * failed and will set also an error in the mail operation
1964 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1965 TnyFolderStore *into,
1966 const gchar *new_name)
1968 if (TNY_IS_ACCOUNT (into) &&
1969 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1970 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1972 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1973 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1974 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1975 _CS("ckdg_ib_folder_already_exists"));
1982 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1984 TnyFolderStore *parent,
1985 gboolean delete_original,
1986 XferFolderAsyncUserCallback user_callback,
1989 ModestMailOperationPrivate *priv = NULL;
1990 ModestTnyFolderRules parent_rules = 0, rules;
1991 XFerFolderAsyncHelper *helper = NULL;
1992 const gchar *folder_name = NULL;
1993 const gchar *error_msg;
1995 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1996 g_return_if_fail (TNY_IS_FOLDER (folder));
1997 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2000 folder_name = tny_folder_get_name (folder);
2002 /* Set the error msg */
2003 error_msg = _("mail_in_ui_folder_move_target_error");
2005 /* Get account and set it into mail_operation */
2006 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2007 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2008 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2010 /* Get folder rules */
2011 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2012 if (TNY_IS_FOLDER (parent))
2013 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2015 /* Apply operation constraints */
2016 if ((gpointer) parent == (gpointer) folder ||
2017 (!TNY_IS_FOLDER_STORE (parent)) ||
2018 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2021 } else if (TNY_IS_FOLDER (parent) &&
2022 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2026 } else if (TNY_IS_FOLDER (parent) &&
2027 TNY_IS_FOLDER_STORE (folder) &&
2028 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2029 TNY_FOLDER_STORE (folder))) {
2030 /* Do not move a parent into a child */
2032 } else if (TNY_IS_FOLDER_STORE (parent) &&
2033 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2034 /* Check that the new folder name is not used by any
2037 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2038 /* Check that the new folder name is not used by any
2039 special local folder */
2042 /* Create the helper */
2043 helper = g_slice_new0 (XFerFolderAsyncHelper);
2044 helper->mail_op = g_object_ref (self);
2045 helper->user_callback = user_callback;
2046 helper->user_data = user_data;
2048 /* Move/Copy folder */
2049 modest_mail_operation_notify_start (self);
2050 tny_folder_copy_async (folder,
2052 tny_folder_get_name (folder),
2055 transfer_folder_status_cb,
2061 /* Set status failed and set an error */
2062 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2063 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2064 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2067 /* Call the user callback if exists */
2069 user_callback (self, NULL, user_data);
2071 /* Notify the queue */
2072 modest_mail_operation_notify_end (self);
2076 modest_mail_operation_rename_folder (ModestMailOperation *self,
2079 XferFolderAsyncUserCallback user_callback,
2082 ModestMailOperationPrivate *priv;
2083 ModestTnyFolderRules rules;
2084 XFerFolderAsyncHelper *helper;
2086 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2087 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2088 g_return_if_fail (name);
2090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2092 /* Get account and set it into mail_operation */
2093 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2094 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2096 /* Check folder rules */
2097 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2098 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2100 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2103 TnyFolderStore *into;
2105 into = tny_folder_get_folder_store (folder);
2107 /* Check that the new folder name is not used by any
2108 special local folder */
2109 if (new_name_valid_if_local_account (priv, into, name)) {
2110 /* Create the helper */
2111 helper = g_slice_new0 (XFerFolderAsyncHelper);
2112 helper->mail_op = g_object_ref(self);
2113 helper->user_callback = user_callback;
2114 helper->user_data = user_data;
2116 /* Rename. Camel handles folder subscription/unsubscription */
2117 modest_mail_operation_notify_start (self);
2118 tny_folder_copy_async (folder, into, name, TRUE,
2120 transfer_folder_status_cb,
2125 g_object_unref (into);
2130 /* Set status failed and set an error */
2131 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2132 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2133 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2134 _("FIXME: unable to rename"));
2137 user_callback (self, NULL, user_data);
2139 /* Notify about operation end */
2140 modest_mail_operation_notify_end (self);
2143 /* ******************************************************************* */
2144 /* ************************** MSG ACTIONS ************************* */
2145 /* ******************************************************************* */
2148 modest_mail_operation_get_msg (ModestMailOperation *self,
2150 GetMsgAsyncUserCallback user_callback,
2153 GetMsgInfo *helper = NULL;
2155 ModestMailOperationPrivate *priv;
2157 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2158 g_return_if_fail (TNY_IS_HEADER (header));
2160 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2161 folder = tny_header_get_folder (header);
2163 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2167 /* Get account and set it into mail_operation */
2168 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2170 /* Check for cached messages */
2171 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2172 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2174 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2176 /* Create the helper */
2177 helper = g_slice_new0 (GetMsgInfo);
2178 helper->header = g_object_ref (header);
2179 helper->mail_op = g_object_ref (self);
2180 helper->user_callback = user_callback;
2181 helper->user_data = user_data;
2182 helper->destroy_notify = NULL;
2183 helper->last_total_bytes = 0;
2184 helper->sum_total_bytes = 0;
2185 helper->total_bytes = tny_header_get_message_size (header);
2187 modest_mail_operation_notify_start (self);
2189 /* notify about the start of the operation */
2190 ModestMailOperationState *state;
2191 state = modest_mail_operation_clone_state (self);
2194 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2197 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2199 g_object_unref (G_OBJECT (folder));
2203 get_msg_status_cb (GObject *obj,
2207 GetMsgInfo *helper = NULL;
2209 g_return_if_fail (status != NULL);
2211 /* Show only the status information we want */
2212 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2215 helper = (GetMsgInfo *) user_data;
2216 g_return_if_fail (helper != NULL);
2218 /* Notify progress */
2219 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2220 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2224 get_msg_async_cb (TnyFolder *folder,
2230 GetMsgInfo *info = NULL;
2231 ModestMailOperationPrivate *priv = NULL;
2234 info = (GetMsgInfo *) user_data;
2236 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2239 if (info->more_msgs) {
2240 tny_iterator_next (info->more_msgs);
2241 finished = (tny_iterator_is_done (info->more_msgs));
2243 finished = (priv->done == priv->total) ? TRUE : FALSE;
2246 /* If canceled by the user, ignore the error given by Tinymail */
2247 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2251 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2253 priv->error = g_error_copy ((const GError *) err);
2254 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2257 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2258 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2261 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2262 /* Set the success status before calling the user callback */
2263 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2267 /* Call the user callback */
2268 if (info->user_callback)
2269 info->user_callback (info->mail_op, info->header, canceled,
2270 msg, err, info->user_data);
2272 /* Notify about operation end if this is the last callback */
2274 /* Free user data */
2275 if (info->destroy_notify)
2276 info->destroy_notify (info->user_data);
2278 /* Notify about operation end */
2279 modest_mail_operation_notify_end (info->mail_op);
2282 if (info->more_msgs)
2283 g_object_unref (info->more_msgs);
2284 g_object_unref (info->header);
2285 g_object_unref (info->mail_op);
2286 g_slice_free (GetMsgInfo, info);
2287 } else if (info->more_msgs) {
2288 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2289 TnyFolder *folder = tny_header_get_folder (header);
2291 g_object_unref (info->header);
2292 info->header = g_object_ref (header);
2294 /* Retrieve the next message */
2295 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2297 g_object_unref (header);
2298 g_object_unref (folder);
2300 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2305 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2306 TnyList *header_list,
2307 GetMsgAsyncUserCallback user_callback,
2309 GDestroyNotify notify)
2311 ModestMailOperationPrivate *priv = NULL;
2313 TnyIterator *iter = NULL;
2314 gboolean has_uncached_messages;
2316 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2318 /* Init mail operation */
2319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2320 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2322 priv->total = tny_list_get_length(header_list);
2324 /* Check uncached messages */
2325 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2326 !has_uncached_messages && !tny_iterator_is_done (iter);
2327 tny_iterator_next (iter)) {
2330 header = (TnyHeader *) tny_iterator_get_current (iter);
2331 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2332 has_uncached_messages = TRUE;
2333 g_object_unref (header);
2335 g_object_unref (iter);
2336 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2338 /* Get account and set it into mail_operation */
2339 if (tny_list_get_length (header_list) >= 1) {
2340 TnyIterator *iterator = tny_list_create_iterator (header_list);
2341 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2343 TnyFolder *folder = tny_header_get_folder (header);
2345 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2346 g_object_unref (folder);
2348 g_object_unref (header);
2350 g_object_unref (iterator);
2353 msg_list_size = compute_message_list_size (header_list);
2355 modest_mail_operation_notify_start (self);
2356 iter = tny_list_create_iterator (header_list);
2357 if (!tny_iterator_is_done (iter)) {
2358 /* notify about the start of the operation */
2359 ModestMailOperationState *state;
2360 state = modest_mail_operation_clone_state (self);
2363 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2366 GetMsgInfo *msg_info = NULL;
2367 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2368 TnyFolder *folder = tny_header_get_folder (header);
2370 /* Create the message info */
2371 msg_info = g_slice_new0 (GetMsgInfo);
2372 msg_info->mail_op = g_object_ref (self);
2373 msg_info->header = g_object_ref (header);
2374 msg_info->more_msgs = g_object_ref (iter);
2375 msg_info->user_callback = user_callback;
2376 msg_info->user_data = user_data;
2377 msg_info->destroy_notify = notify;
2378 msg_info->last_total_bytes = 0;
2379 msg_info->sum_total_bytes = 0;
2380 msg_info->total_bytes = msg_list_size;
2382 /* The callback will call it per each header */
2383 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2385 /* Free and go on */
2386 g_object_unref (header);
2387 g_object_unref (folder);
2388 g_slice_free (ModestMailOperationState, state);
2390 g_object_unref (iter);
2395 remove_msgs_async_cb (TnyFolder *folder,
2400 gboolean expunge, leave_on_server;
2401 const gchar *account_name;
2403 TnyAccount *account;
2404 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2405 ModestMailOperation *self;
2406 ModestMailOperationPrivate *priv;
2408 self = (ModestMailOperation *) user_data;
2409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2411 if (canceled || err) {
2412 /* If canceled by the user, ignore the error given by Tinymail */
2414 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2416 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2417 priv->error = g_error_copy ((const GError *) err);
2418 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2421 modest_mail_operation_notify_end (self);
2422 g_object_unref (self);
2426 account = tny_folder_get_account (folder);
2427 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2429 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2431 proto = tny_account_get_proto (account);
2432 g_object_unref (account);
2435 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2437 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2438 modest_tny_folder_is_remote_folder (folder) == FALSE)
2444 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2449 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2451 gboolean remove_to_trash /*ignored*/)
2453 TnyFolder *folder = NULL;
2454 ModestMailOperationPrivate *priv;
2455 TnyIterator *iter = NULL;
2456 TnyHeader *header = NULL;
2457 TnyList *remove_headers = NULL;
2458 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2460 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2461 g_return_if_fail (TNY_IS_LIST (headers));
2463 if (remove_to_trash)
2464 g_warning ("remove to trash is not implemented");
2466 if (tny_list_get_length(headers) == 0) {
2467 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2468 goto cleanup; /* nothing to do */
2471 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2472 remove_headers = g_object_ref(headers);
2474 /* Get folder from first header and sync it */
2475 iter = tny_list_create_iterator (headers);
2476 header = TNY_HEADER (tny_iterator_get_current (iter));
2478 folder = tny_header_get_folder (header);
2479 if (!TNY_IS_FOLDER(folder)) {
2480 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2484 /* Don't remove messages that are being sent */
2485 if (modest_tny_folder_is_local_folder (folder)) {
2486 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2488 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2489 TnyTransportAccount *traccount = NULL;
2490 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2491 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2493 ModestTnySendQueueStatus status;
2494 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2495 TnyIterator *iter = tny_list_create_iterator(headers);
2496 g_object_unref(remove_headers);
2497 remove_headers = TNY_LIST(tny_simple_list_new());
2498 while (!tny_iterator_is_done(iter)) {
2500 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2501 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2502 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2503 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2504 tny_list_append(remove_headers, G_OBJECT(hdr));
2506 g_object_unref(hdr);
2508 tny_iterator_next(iter);
2510 g_object_unref(iter);
2511 g_object_unref(traccount);
2515 /* Get account and set it into mail_operation */
2516 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2517 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2518 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2520 /* remove message from folder */
2521 modest_mail_operation_notify_start (self);
2522 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2523 NULL, g_object_ref (self));
2527 g_object_unref (remove_headers);
2529 g_object_unref (header);
2531 g_object_unref (iter);
2533 g_object_unref (folder);
2537 notify_progress_of_multiple_messages (ModestMailOperation *self,
2539 gint *last_total_bytes,
2540 gint *sum_total_bytes,
2542 gboolean increment_done)
2544 ModestMailOperationPrivate *priv;
2545 ModestMailOperationState *state;
2546 gboolean is_num_bytes = FALSE;
2548 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2550 /* We know that tinymail sends us information about
2551 * transferred bytes with this particular message
2553 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2554 * I just added the 'if' so we don't get runtime warning)
2556 if (status->message)
2557 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2559 state = modest_mail_operation_clone_state (self);
2560 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2561 /* We know that we're in a different message when the
2562 total number of bytes to transfer is different. Of
2563 course it could fail if we're transferring messages
2564 of the same size, but this is a workarround */
2565 if (status->of_total != *last_total_bytes) {
2566 /* We need to increment the done when there is
2567 no information about each individual
2568 message, we need to do this in message
2569 transfers, and we don't do it for getting
2573 *sum_total_bytes += *last_total_bytes;
2574 *last_total_bytes = status->of_total;
2576 state->bytes_done += status->position + *sum_total_bytes;
2577 state->bytes_total = total_bytes;
2579 /* Notify the status change. Only notify about changes
2580 referred to bytes */
2581 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2585 g_slice_free (ModestMailOperationState, state);
2589 transfer_msgs_status_cb (GObject *obj,
2593 XFerMsgsAsyncHelper *helper;
2595 g_return_if_fail (status != NULL);
2597 /* Show only the status information we want */
2598 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2601 helper = (XFerMsgsAsyncHelper *) user_data;
2602 g_return_if_fail (helper != NULL);
2604 /* Notify progress */
2605 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2606 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2611 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2613 XFerMsgsAsyncHelper *helper;
2614 ModestMailOperation *self;
2615 ModestMailOperationPrivate *priv;
2616 gboolean finished = TRUE;
2618 helper = (XFerMsgsAsyncHelper *) user_data;
2619 self = helper->mail_op;
2621 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2624 priv->error = g_error_copy (err);
2626 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2627 } else if (cancelled) {
2628 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2629 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2630 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2631 _("Error trying to refresh the contents of %s"),
2632 tny_folder_get_name (folder));
2633 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2634 if (helper->more_msgs) {
2635 /* We'll transfer the next message in the list */
2636 tny_iterator_next (helper->more_msgs);
2637 if (!tny_iterator_is_done (helper->more_msgs)) {
2638 GObject *next_header;
2639 g_object_unref (helper->headers);
2640 helper->headers = tny_simple_list_new ();
2641 next_header = tny_iterator_get_current (helper->more_msgs);
2642 tny_list_append (helper->headers, next_header);
2643 g_object_unref (next_header);
2650 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2656 /* Update folder counts */
2657 tny_folder_poke_status (folder);
2658 tny_folder_poke_status (helper->dest_folder);
2660 /* Notify about operation end */
2661 modest_mail_operation_notify_end (self);
2663 /* If user defined callback function was defined, call it */
2664 if (helper->user_callback) {
2665 /* This is not a GDK lock because we are a Tinymail callback and
2666 * Tinymail already acquires the Gdk lock */
2668 /* no gdk_threads_enter (), CHECKED */
2669 helper->user_callback (self, helper->user_data);
2670 /* no gdk_threads_leave (), CHECKED */
2674 if (helper->more_msgs)
2675 g_object_unref (helper->more_msgs);
2676 if (helper->headers)
2677 g_object_unref (helper->headers);
2678 if (helper->dest_folder)
2679 g_object_unref (helper->dest_folder);
2680 if (helper->mail_op)
2681 g_object_unref (helper->mail_op);
2682 g_slice_free (XFerMsgsAsyncHelper, helper);
2684 /* Transfer more messages */
2685 tny_folder_transfer_msgs_async (folder,
2687 helper->dest_folder,
2690 transfer_msgs_status_cb,
2696 compute_message_list_size (TnyList *headers)
2701 iter = tny_list_create_iterator (headers);
2702 while (!tny_iterator_is_done (iter)) {
2703 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2704 size += tny_header_get_message_size (header);
2705 g_object_unref (header);
2706 tny_iterator_next (iter);
2708 g_object_unref (iter);
2714 compute_message_array_size (GPtrArray *headers)
2719 for (i = 0; i < headers->len; i++) {
2720 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2721 size += tny_header_get_message_size (header);
2729 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2732 gboolean delete_original,
2733 XferMsgsAsyncUserCallback user_callback,
2736 ModestMailOperationPrivate *priv = NULL;
2737 TnyIterator *iter = NULL;
2738 TnyFolder *src_folder = NULL;
2739 XFerMsgsAsyncHelper *helper = NULL;
2740 TnyHeader *header = NULL;
2741 ModestTnyFolderRules rules = 0;
2742 TnyAccount *dst_account = NULL;
2743 gboolean leave_on_server;
2745 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2746 g_return_if_fail (headers && TNY_IS_LIST (headers));
2747 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2750 priv->total = tny_list_get_length (headers);
2752 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2753 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2755 /* Apply folder rules */
2756 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2757 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2758 /* Set status failed and set an error */
2759 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2760 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2761 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2762 _CS("ckct_ib_unable_to_paste_here"));
2763 /* Notify the queue */
2764 modest_mail_operation_notify_end (self);
2768 /* Get source folder */
2769 iter = tny_list_create_iterator (headers);
2770 header = TNY_HEADER (tny_iterator_get_current (iter));
2772 src_folder = tny_header_get_folder (header);
2773 g_object_unref (header);
2775 g_object_unref (iter);
2777 if (src_folder == NULL) {
2778 /* Notify the queue */
2779 modest_mail_operation_notify_end (self);
2781 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2786 /* Check folder source and destination */
2787 if (src_folder == folder) {
2788 /* Set status failed and set an error */
2789 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2790 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2791 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2792 _("mail_in_ui_folder_copy_target_error"));
2794 /* Notify the queue */
2795 modest_mail_operation_notify_end (self);
2798 g_object_unref (src_folder);
2802 /* Create the helper */
2803 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2804 helper->mail_op = g_object_ref(self);
2805 helper->dest_folder = g_object_ref(folder);
2806 helper->user_callback = user_callback;
2807 helper->user_data = user_data;
2808 helper->delete = delete_original;
2809 helper->last_total_bytes = 0;
2810 helper->sum_total_bytes = 0;
2811 helper->total_bytes = compute_message_list_size (headers);
2813 /* Get account and set it into mail_operation */
2814 priv->account = modest_tny_folder_get_account (src_folder);
2815 dst_account = modest_tny_folder_get_account (folder);
2817 if (priv->account == dst_account) {
2818 /* Transfer all messages at once using the fast
2819 * method. Note that depending on the server this
2820 * might not be that fast, and might not be
2821 * user-cancellable either */
2822 helper->headers = g_object_ref (headers);
2823 helper->more_msgs = NULL;
2825 /* Transfer messages one by one so the user can cancel
2828 helper->headers = tny_simple_list_new ();
2829 helper->more_msgs = tny_list_create_iterator (headers);
2830 hdr = tny_iterator_get_current (helper->more_msgs);
2831 tny_list_append (helper->headers, hdr);
2832 g_object_unref (hdr);
2835 /* If leave_on_server is set to TRUE then don't use
2836 delete_original, we always pass FALSE. This is because
2837 otherwise tinymail will try to sync the source folder and
2838 this could cause an error if we're offline while
2839 transferring an already downloaded message from a POP
2841 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2842 MODEST_PROTOCOL_STORE_POP) {
2843 const gchar *account_name;
2845 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2846 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2849 leave_on_server = FALSE;
2852 modest_mail_operation_notify_start (self);
2853 tny_folder_transfer_msgs_async (src_folder,
2856 (leave_on_server) ? FALSE : delete_original,
2858 transfer_msgs_status_cb,
2860 g_object_unref (src_folder);
2861 g_object_unref (dst_account);
2866 on_refresh_folder (TnyFolder *folder,
2871 RefreshAsyncHelper *helper = NULL;
2872 ModestMailOperation *self = NULL;
2873 ModestMailOperationPrivate *priv = NULL;
2875 helper = (RefreshAsyncHelper *) user_data;
2876 self = helper->mail_op;
2877 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2879 g_return_if_fail(priv!=NULL);
2882 priv->error = g_error_copy (error);
2883 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2888 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2889 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2890 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2891 _("Error trying to refresh the contents of %s"),
2892 tny_folder_get_name (folder));
2896 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2899 /* Call user defined callback, if it exists */
2900 if (helper->user_callback) {
2902 /* This is not a GDK lock because we are a Tinymail callback and
2903 * Tinymail already acquires the Gdk lock */
2904 helper->user_callback (self, folder, helper->user_data);
2908 g_slice_free (RefreshAsyncHelper, helper);
2910 /* Notify about operation end */
2911 modest_mail_operation_notify_end (self);
2912 g_object_unref(self);
2916 on_refresh_folder_status_update (GObject *obj,
2920 RefreshAsyncHelper *helper = NULL;
2921 ModestMailOperation *self = NULL;
2922 ModestMailOperationPrivate *priv = NULL;
2923 ModestMailOperationState *state;
2925 g_return_if_fail (user_data != NULL);
2926 g_return_if_fail (status != NULL);
2928 /* Show only the status information we want */
2929 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2932 helper = (RefreshAsyncHelper *) user_data;
2933 self = helper->mail_op;
2934 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2936 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2938 priv->done = status->position;
2939 priv->total = status->of_total;
2941 state = modest_mail_operation_clone_state (self);
2943 /* This is not a GDK lock because we are a Tinymail callback and
2944 * Tinymail already acquires the Gdk lock */
2945 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2947 g_slice_free (ModestMailOperationState, state);
2951 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2953 RefreshAsyncUserCallback user_callback,
2956 ModestMailOperationPrivate *priv = NULL;
2957 RefreshAsyncHelper *helper = NULL;
2959 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2961 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2963 /* Get account and set it into mail_operation */
2964 priv->account = modest_tny_folder_get_account (folder);
2965 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2967 /* Create the helper */
2968 helper = g_slice_new0 (RefreshAsyncHelper);
2969 helper->mail_op = g_object_ref(self);
2970 helper->user_callback = user_callback;
2971 helper->user_data = user_data;
2973 modest_mail_operation_notify_start (self);
2975 /* notify that the operation was started */
2976 ModestMailOperationState *state;
2977 state = modest_mail_operation_clone_state (self);
2980 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2983 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2985 tny_folder_refresh_async (folder,
2987 on_refresh_folder_status_update,
2992 run_queue_stop (ModestTnySendQueue *queue,
2993 ModestMailOperation *self)
2995 ModestMailOperationPrivate *priv;
2997 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2998 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3001 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3003 modest_mail_operation_notify_end (self);
3004 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3005 g_object_unref (self);
3008 modest_mail_operation_run_queue (ModestMailOperation *self,
3009 ModestTnySendQueue *queue)
3011 ModestMailOperationPrivate *priv;
3013 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3014 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3015 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3017 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3018 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3019 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3021 modest_mail_operation_notify_start (self);
3022 g_object_ref (self);
3023 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3027 sync_folder_finish_callback (TnyFolder *self,
3033 ModestMailOperation *mail_op;
3034 ModestMailOperationPrivate *priv;
3036 mail_op = (ModestMailOperation *) user_data;
3037 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3039 /* If canceled by the user, ignore the error given by Tinymail */
3041 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3043 /* If the operation was a sync then the status is
3044 failed, but if it's part of another operation then
3045 just set it as finished with errors */
3046 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3047 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3049 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3050 priv->error = g_error_copy ((const GError *) err);
3051 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3053 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3056 modest_mail_operation_notify_end (mail_op);
3057 g_object_unref (mail_op);
3061 modest_mail_operation_sync_folder (ModestMailOperation *self,
3062 TnyFolder *folder, gboolean expunge)
3064 ModestMailOperationPrivate *priv;
3066 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3067 g_return_if_fail (TNY_IS_FOLDER (folder));
3068 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3070 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3071 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3072 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3074 modest_mail_operation_notify_start (self);
3075 g_object_ref (self);
3076 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3080 modest_mail_operation_notify_start (ModestMailOperation *self)
3082 ModestMailOperationPrivate *priv = NULL;
3084 g_return_if_fail (self);
3086 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3088 /* Ensure that all the fields are filled correctly */
3089 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3091 /* Notify the observers about the mail operation. We do not
3092 wrapp this emission because we assume that this function is
3093 always called from within the main lock */
3094 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3099 * It's used by the mail operation queue to notify the observers
3100 * attached to that signal that the operation finished. We need to use
3101 * that because tinymail does not give us the progress of a given
3102 * operation when it finishes (it directly calls the operation
3106 modest_mail_operation_notify_end (ModestMailOperation *self)
3108 ModestMailOperationPrivate *priv = NULL;
3110 g_return_if_fail (self);
3112 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3114 /* Notify the observers about the mail operation end. We do
3115 not wrapp this emission because we assume that this
3116 function is always called from within the main lock */
3117 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3119 /* Remove the error user data */
3120 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3121 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3125 modest_mail_operation_get_account (ModestMailOperation *self)
3127 ModestMailOperationPrivate *priv = NULL;
3129 g_return_val_if_fail (self, NULL);
3131 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3133 return (priv->account) ? g_object_ref (priv->account) : NULL;
3137 modest_mail_operation_noop (ModestMailOperation *self)
3139 ModestMailOperationPrivate *priv = NULL;
3141 g_return_if_fail (self);
3143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3144 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3145 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3149 /* This mail operation does nothing actually */
3150 modest_mail_operation_notify_start (self);
3151 modest_mail_operation_notify_end (self);
3156 modest_mail_operation_to_string (ModestMailOperation *self)
3158 const gchar *type, *status, *account_id;
3159 ModestMailOperationPrivate *priv = NULL;
3161 g_return_val_if_fail (self, NULL);
3163 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3165 /* new operations don't have anything interesting */
3166 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3167 return g_strdup_printf ("%p <new operation>", self);
3169 switch (priv->op_type) {
3170 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3171 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3172 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3173 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3174 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3175 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3176 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3177 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3178 default: type = "UNEXPECTED"; break;
3181 switch (priv->status) {
3182 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3183 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3184 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3185 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3186 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3187 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3188 default: status= "UNEXPECTED"; break;
3191 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3193 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3194 priv->done, priv->total,
3195 priv->error && priv->error->message ? priv->error->message : "");