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"
67 * Remove all these #ifdef stuff when the tinymail's idle calls become
70 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
72 /* 'private'/'protected' functions */
73 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
74 static void modest_mail_operation_init (ModestMailOperation *obj);
75 static void modest_mail_operation_finalize (GObject *obj);
77 static void get_msg_async_cb (TnyFolder *folder,
83 static void get_msg_status_cb (GObject *obj,
87 static void modest_mail_operation_notify_start (ModestMailOperation *self);
88 static void modest_mail_operation_notify_end (ModestMailOperation *self);
90 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
92 gint *last_total_bytes,
93 gint *sum_total_bytes,
95 gboolean increment_done);
97 static guint compute_message_list_size (TnyList *headers);
99 static guint compute_message_array_size (GPtrArray *headers);
101 static int compare_headers_by_date (gconstpointer a,
104 enum _ModestMailOperationSignals
106 PROGRESS_CHANGED_SIGNAL,
107 OPERATION_STARTED_SIGNAL,
108 OPERATION_FINISHED_SIGNAL,
112 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
113 struct _ModestMailOperationPrivate {
119 ErrorCheckingUserCallback error_checking;
120 gpointer error_checking_user_data;
121 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
122 ModestMailOperationStatus status;
123 ModestMailOperationTypeOperation op_type;
126 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
127 MODEST_TYPE_MAIL_OPERATION, \
128 ModestMailOperationPrivate))
130 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
131 priv->status = new_status;\
136 GetMsgAsyncUserCallback user_callback;
138 TnyIterator *more_msgs;
140 ModestMailOperation *mail_op;
141 GDestroyNotify destroy_notify;
142 gint last_total_bytes;
143 gint sum_total_bytes;
147 typedef struct _RefreshAsyncHelper {
148 ModestMailOperation *mail_op;
149 RefreshAsyncUserCallback user_callback;
151 } RefreshAsyncHelper;
153 typedef struct _XFerMsgsAsyncHelper
155 ModestMailOperation *mail_op;
157 TnyIterator *more_msgs;
158 TnyFolder *dest_folder;
159 XferMsgsAsyncUserCallback user_callback;
162 gint last_total_bytes;
163 gint sum_total_bytes;
165 } XFerMsgsAsyncHelper;
167 typedef struct _XFerFolderAsyncHelper
169 ModestMailOperation *mail_op;
170 XferFolderAsyncUserCallback user_callback;
172 } XFerFolderAsyncHelper;
174 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
178 static void modest_mail_operation_create_msg (ModestMailOperation *self,
179 const gchar *from, const gchar *to,
180 const gchar *cc, const gchar *bcc,
181 const gchar *subject, const gchar *plain_body,
182 const gchar *html_body, const GList *attachments_list,
183 const GList *images_list,
184 TnyHeaderFlags priority_flags,
185 ModestMailOperationCreateMsgCallback callback,
188 static gboolean idle_notify_queue (gpointer data);
191 ModestMailOperation *mail_op;
199 GList *attachments_list;
201 TnyHeaderFlags priority_flags;
202 ModestMailOperationCreateMsgCallback callback;
208 ModestMailOperation *mail_op;
210 ModestMailOperationCreateMsgCallback callback;
215 static GObjectClass *parent_class = NULL;
217 static guint signals[NUM_SIGNALS] = {0};
220 modest_mail_operation_get_type (void)
222 static GType my_type = 0;
224 static const GTypeInfo my_info = {
225 sizeof(ModestMailOperationClass),
226 NULL, /* base init */
227 NULL, /* base finalize */
228 (GClassInitFunc) modest_mail_operation_class_init,
229 NULL, /* class finalize */
230 NULL, /* class data */
231 sizeof(ModestMailOperation),
233 (GInstanceInitFunc) modest_mail_operation_init,
236 my_type = g_type_register_static (G_TYPE_OBJECT,
237 "ModestMailOperation",
244 modest_mail_operation_class_init (ModestMailOperationClass *klass)
246 GObjectClass *gobject_class;
247 gobject_class = (GObjectClass*) klass;
249 parent_class = g_type_class_peek_parent (klass);
250 gobject_class->finalize = modest_mail_operation_finalize;
252 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
255 * ModestMailOperation::progress-changed
256 * @self: the #MailOperation that emits the signal
257 * @user_data: user data set when the signal handler was connected
259 * Emitted when the progress of a mail operation changes
261 signals[PROGRESS_CHANGED_SIGNAL] =
262 g_signal_new ("progress-changed",
263 G_TYPE_FROM_CLASS (gobject_class),
265 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
267 g_cclosure_marshal_VOID__POINTER,
268 G_TYPE_NONE, 1, G_TYPE_POINTER);
272 * This signal is issued whenever a mail operation starts, and
273 * starts mean when the tinymail operation is issued. This
274 * means that it could happen that something wrong happens and
275 * the tinymail function is never called. In this situation a
276 * operation-finished will be issued without any
279 signals[OPERATION_STARTED_SIGNAL] =
280 g_signal_new ("operation-started",
281 G_TYPE_FROM_CLASS (gobject_class),
283 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
285 g_cclosure_marshal_VOID__VOID,
290 * This signal is issued whenever a mail operation
291 * finishes. Note that this signal could be issued without any
292 * previous "operation-started" signal, because this last one
293 * is only issued when the tinymail operation is successfully
296 signals[OPERATION_FINISHED_SIGNAL] =
297 g_signal_new ("operation-finished",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
302 g_cclosure_marshal_VOID__VOID,
307 modest_mail_operation_init (ModestMailOperation *obj)
309 ModestMailOperationPrivate *priv;
311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
313 priv->account = NULL;
314 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
315 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
320 priv->error_checking = NULL;
321 priv->error_checking_user_data = NULL;
325 modest_mail_operation_finalize (GObject *obj)
327 ModestMailOperationPrivate *priv;
329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
334 g_error_free (priv->error);
338 g_object_unref (priv->source);
342 g_object_unref (priv->account);
343 priv->account = NULL;
347 G_OBJECT_CLASS(parent_class)->finalize (obj);
351 modest_mail_operation_new (GObject *source)
353 ModestMailOperation *obj;
354 ModestMailOperationPrivate *priv;
356 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
360 priv->source = g_object_ref(source);
366 modest_mail_operation_new_with_error_handling (GObject *source,
367 ErrorCheckingUserCallback error_handler,
369 ErrorCheckingUserDataDestroyer error_handler_destroyer)
371 ModestMailOperation *obj;
372 ModestMailOperationPrivate *priv;
374 obj = modest_mail_operation_new (source);
375 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
377 g_return_val_if_fail (error_handler != NULL, obj);
378 priv->error_checking = error_handler;
379 priv->error_checking_user_data = user_data;
380 priv->error_checking_user_data_destroyer = error_handler_destroyer;
386 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
388 ModestMailOperationPrivate *priv;
390 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
393 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
395 /* Call the user callback */
396 if (priv->error_checking != NULL)
397 priv->error_checking (self, priv->error_checking_user_data);
401 ModestMailOperationTypeOperation
402 modest_mail_operation_get_type_operation (ModestMailOperation *self)
404 ModestMailOperationPrivate *priv;
406 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
407 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
411 return priv->op_type;
415 modest_mail_operation_is_mine (ModestMailOperation *self,
418 ModestMailOperationPrivate *priv;
420 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
424 if (priv->source == NULL) return FALSE;
426 return priv->source == me;
430 modest_mail_operation_get_source (ModestMailOperation *self)
432 ModestMailOperationPrivate *priv;
434 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
439 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
443 return (priv->source) ? g_object_ref (priv->source) : NULL;
446 ModestMailOperationStatus
447 modest_mail_operation_get_status (ModestMailOperation *self)
449 ModestMailOperationPrivate *priv;
451 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
452 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
453 MODEST_MAIL_OPERATION_STATUS_INVALID);
455 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
457 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
458 return MODEST_MAIL_OPERATION_STATUS_INVALID;
465 modest_mail_operation_get_error (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self, NULL);
470 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
475 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
483 modest_mail_operation_cancel (ModestMailOperation *self)
485 ModestMailOperationPrivate *priv;
486 gboolean canceled = FALSE;
488 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
493 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
495 /* Cancel the mail operation */
496 g_return_val_if_fail (priv->account, FALSE);
497 tny_account_cancel (priv->account);
499 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
500 ModestTnySendQueue *queue;
501 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
503 /* Cancel the sending of the following next messages */
504 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
511 modest_mail_operation_get_task_done (ModestMailOperation *self)
513 ModestMailOperationPrivate *priv;
515 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 modest_mail_operation_get_task_total (ModestMailOperation *self)
525 ModestMailOperationPrivate *priv;
527 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
530 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
535 modest_mail_operation_is_finished (ModestMailOperation *self)
537 ModestMailOperationPrivate *priv;
538 gboolean retval = FALSE;
540 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
543 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
546 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
547 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
548 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
558 * Creates an image of the current state of a mail operation, the
559 * caller must free it
561 static ModestMailOperationState *
562 modest_mail_operation_clone_state (ModestMailOperation *self)
564 ModestMailOperationState *state;
565 ModestMailOperationPrivate *priv;
567 /* FIXME: this should be fixed properly
569 * in some cases, priv was NULL, so checking here to
572 g_return_val_if_fail (self, NULL);
573 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
574 g_return_val_if_fail (priv, NULL);
579 state = g_slice_new (ModestMailOperationState);
581 state->status = priv->status;
582 state->op_type = priv->op_type;
583 state->done = priv->done;
584 state->total = priv->total;
585 state->finished = modest_mail_operation_is_finished (self);
586 state->bytes_done = 0;
587 state->bytes_total = 0;
592 /* ******************************************************************* */
593 /* ************************** SEND ACTIONS ************************* */
594 /* ******************************************************************* */
597 modest_mail_operation_send_mail (ModestMailOperation *self,
598 TnyTransportAccount *transport_account,
601 TnySendQueue *send_queue = NULL;
602 ModestMailOperationPrivate *priv;
604 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
605 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
606 g_return_if_fail (msg && TNY_IS_MSG (msg));
608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
610 /* Get account and set it into mail_operation */
611 priv->account = g_object_ref (transport_account);
612 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
616 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
617 if (!TNY_IS_SEND_QUEUE(send_queue)) {
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
620 "modest: could not find send queue for account\n");
621 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
622 modest_mail_operation_notify_end (self);
625 /* Add the msg to the queue */
626 modest_mail_operation_notify_start (self);
628 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
629 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE);
631 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
632 modest_mail_operation_notify_end (self);
639 idle_create_msg_cb (gpointer idle_data)
641 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
643 /* This is a GDK lock because we are an idle callback and
644 * info->callback can contain Gtk+ code */
646 gdk_threads_enter (); /* CHECKED */
647 info->callback (info->mail_op, info->msg, info->userdata);
649 g_object_unref (info->mail_op);
651 g_object_unref (info->msg);
652 g_slice_free (CreateMsgIdleInfo, info);
653 gdk_threads_leave (); /* CHECKED */
659 create_msg_thread (gpointer thread_data)
661 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
662 TnyMsg *new_msg = NULL;
663 ModestMailOperationPrivate *priv;
665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
666 if (info->html_body == NULL) {
667 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
668 info->bcc, info->subject, info->plain_body,
669 info->attachments_list);
671 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
672 info->bcc, info->subject, info->html_body,
673 info->plain_body, info->attachments_list,
680 /* Set priority flags in message */
681 header = tny_msg_get_header (new_msg);
682 tny_header_set_flag (header, info->priority_flags);
684 /* Set attachment flags in message */
685 if (info->attachments_list != NULL)
686 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
688 g_object_unref (G_OBJECT(header));
690 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
692 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
693 "modest: failed to create a new msg\n");
701 g_free (info->plain_body);
702 g_free (info->html_body);
703 g_free (info->subject);
704 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
705 g_list_free (info->attachments_list);
706 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
707 g_list_free (info->images_list);
709 if (info->callback) {
710 CreateMsgIdleInfo *idle_info;
711 idle_info = g_slice_new0 (CreateMsgIdleInfo);
712 idle_info->mail_op = g_object_ref (info->mail_op);
713 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
714 idle_info->callback = info->callback;
715 idle_info->userdata = info->userdata;
716 g_idle_add (idle_create_msg_cb, idle_info);
718 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
721 g_object_unref (info->mail_op);
722 g_slice_free (CreateMsgInfo, info);
723 if (new_msg) g_object_unref(new_msg);
729 modest_mail_operation_create_msg (ModestMailOperation *self,
730 const gchar *from, const gchar *to,
731 const gchar *cc, const gchar *bcc,
732 const gchar *subject, const gchar *plain_body,
733 const gchar *html_body,
734 const GList *attachments_list,
735 const GList *images_list,
736 TnyHeaderFlags priority_flags,
737 ModestMailOperationCreateMsgCallback callback,
740 CreateMsgInfo *info = NULL;
742 info = g_slice_new0 (CreateMsgInfo);
743 info->mail_op = g_object_ref (self);
745 info->from = g_strdup (from);
746 info->to = g_strdup (to);
747 info->cc = g_strdup (cc);
748 info->bcc = g_strdup (bcc);
749 info->subject = g_strdup (subject);
750 info->plain_body = g_strdup (plain_body);
751 info->html_body = g_strdup (html_body);
752 info->attachments_list = g_list_copy ((GList *) attachments_list);
753 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
754 info->images_list = g_list_copy ((GList *) images_list);
755 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
756 info->priority_flags = priority_flags;
758 info->callback = callback;
759 info->userdata = userdata;
761 g_thread_create (create_msg_thread, info, FALSE, NULL);
766 TnyTransportAccount *transport_account;
771 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
775 ModestMailOperationPrivate *priv = NULL;
776 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
777 TnyFolder *draft_folder = NULL;
778 TnyFolder *outbox_folder = NULL;
779 TnyHeader *header = NULL;
786 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
789 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
790 modest_mail_operation_notify_end (self);
794 /* Call mail operation */
795 modest_mail_operation_send_mail (self, info->transport_account, msg);
797 if (info->draft_msg != NULL) {
798 TnyFolder *folder = NULL;
799 TnyFolder *src_folder = NULL;
800 TnyFolderType folder_type;
801 TnyTransportAccount *transport_account = NULL;
803 /* To remove the old mail from its source folder, we need to get the
804 * transport account of the original draft message (the transport account
805 * might have been changed by the user) */
806 header = tny_msg_get_header (info->draft_msg);
807 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
808 modest_runtime_get_account_store(), header);
809 if (transport_account == NULL)
810 transport_account = g_object_ref(info->transport_account);
811 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
812 TNY_FOLDER_TYPE_DRAFTS);
813 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
814 TNY_FOLDER_TYPE_OUTBOX);
815 g_object_unref(transport_account);
818 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
822 if (!outbox_folder) {
823 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
828 folder = tny_msg_get_folder (info->draft_msg);
829 if (folder == NULL) goto end;
830 folder_type = modest_tny_folder_guess_folder_type (folder);
832 if (folder_type == TNY_FOLDER_TYPE_INVALID)
833 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
835 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
836 src_folder = outbox_folder;
838 src_folder = draft_folder;
840 /* Note: This can fail (with a warning) if the message is not really already in a folder,
841 * because this function requires it to have a UID. */
842 tny_folder_remove_msg (src_folder, header, NULL);
844 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
845 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
847 g_object_unref (folder);
852 g_object_unref (header);
856 g_object_unref (info->draft_msg);
858 g_object_unref (draft_folder);
860 g_object_unref (outbox_folder);
861 if (info->transport_account)
862 g_object_unref (info->transport_account);
863 g_slice_free (SendNewMailInfo, info);
867 modest_mail_operation_send_new_mail (ModestMailOperation *self,
868 TnyTransportAccount *transport_account,
870 const gchar *from, const gchar *to,
871 const gchar *cc, const gchar *bcc,
872 const gchar *subject, const gchar *plain_body,
873 const gchar *html_body,
874 const GList *attachments_list,
875 const GList *images_list,
876 TnyHeaderFlags priority_flags)
878 ModestMailOperationPrivate *priv = NULL;
879 SendNewMailInfo *info;
881 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
882 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
885 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
886 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
887 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
889 /* Check parametters */
891 /* Set status failed and set an error */
892 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
893 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
894 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
895 _("Error trying to send a mail. You need to set at least one recipient"));
898 info = g_slice_new0 (SendNewMailInfo);
899 info->transport_account = transport_account;
900 if (transport_account)
901 g_object_ref (transport_account);
902 info->draft_msg = draft_msg;
904 g_object_ref (draft_msg);
907 modest_mail_operation_notify_start (self);
908 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
909 attachments_list, images_list, priority_flags,
910 modest_mail_operation_send_new_mail_cb, info);
916 TnyTransportAccount *transport_account;
918 SaveToDraftstCallback callback;
922 ModestMailOperation *mailop;
923 } SaveToDraftsAddMsgInfo;
926 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
931 ModestMailOperationPrivate *priv = NULL;
932 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
934 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
937 g_warning ("%s: priv->error != NULL", __FUNCTION__);
938 g_error_free(priv->error);
941 priv->error = (err == NULL) ? NULL : g_error_copy(err);
943 if ((!priv->error) && (info->draft_msg != NULL)) {
944 TnyHeader *header = tny_msg_get_header (info->draft_msg);
945 TnyFolder *src_folder = tny_header_get_folder (header);
947 /* Remove the old draft */
948 tny_folder_remove_msg (src_folder, header, NULL);
950 /* Synchronize to expunge and to update the msg counts */
951 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
952 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
954 g_object_unref (G_OBJECT(header));
955 g_object_unref (G_OBJECT(src_folder));
959 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
961 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
963 /* Call the user callback */
965 info->callback (info->mailop, info->msg, info->user_data);
967 if (info->transport_account)
968 g_object_unref (G_OBJECT(info->transport_account));
970 g_object_unref (G_OBJECT (info->draft_msg));
972 g_object_unref (G_OBJECT(info->drafts));
974 g_object_unref (G_OBJECT (info->msg));
976 modest_mail_operation_notify_end (info->mailop);
977 g_object_unref(info->mailop);
978 g_slice_free (SaveToDraftsAddMsgInfo, info);
983 TnyTransportAccount *transport_account;
985 SaveToDraftstCallback callback;
990 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
994 TnyFolder *drafts = NULL;
995 ModestMailOperationPrivate *priv = NULL;
996 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
998 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1001 if (!(priv->error)) {
1002 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1003 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1004 "modest: failed to create a new msg\n");
1007 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1008 TNY_FOLDER_TYPE_DRAFTS);
1009 if (!drafts && !(priv->error)) {
1010 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1011 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1012 "modest: failed to create a new msg\n");
1017 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1018 cb_info->transport_account = g_object_ref(info->transport_account);
1019 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1020 cb_info->callback = info->callback;
1021 cb_info->user_data = info->user_data;
1022 cb_info->drafts = g_object_ref(drafts);
1023 cb_info->msg = g_object_ref(msg);
1024 cb_info->mailop = g_object_ref(self);
1025 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1028 /* Call the user callback */
1029 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1031 info->callback (self, msg, info->user_data);
1032 modest_mail_operation_notify_end (self);
1036 g_object_unref (G_OBJECT(drafts));
1037 if (info->draft_msg)
1038 g_object_unref (G_OBJECT (info->draft_msg));
1039 if (info->transport_account)
1040 g_object_unref (G_OBJECT(info->transport_account));
1041 g_slice_free (SaveToDraftsInfo, info);
1045 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1046 TnyTransportAccount *transport_account,
1048 const gchar *from, const gchar *to,
1049 const gchar *cc, const gchar *bcc,
1050 const gchar *subject, const gchar *plain_body,
1051 const gchar *html_body,
1052 const GList *attachments_list,
1053 const GList *images_list,
1054 TnyHeaderFlags priority_flags,
1055 SaveToDraftstCallback callback,
1058 ModestMailOperationPrivate *priv = NULL;
1059 SaveToDraftsInfo *info = NULL;
1061 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1062 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1064 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1066 /* Get account and set it into mail_operation */
1067 priv->account = g_object_ref (transport_account);
1068 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1070 info = g_slice_new0 (SaveToDraftsInfo);
1071 info->transport_account = g_object_ref (transport_account);
1072 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1073 info->callback = callback;
1074 info->user_data = user_data;
1076 modest_mail_operation_notify_start (self);
1077 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1078 attachments_list, images_list, priority_flags,
1079 modest_mail_operation_save_to_drafts_cb, info);
1084 ModestMailOperation *mail_op;
1085 TnyMimePart *mime_part;
1087 GetMimePartSizeCallback callback;
1089 } GetMimePartSizeInfo;
1091 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1092 /* We use this folder observer to track the headers that have been
1093 * added to a folder */
1096 TnyList *new_headers;
1097 } InternalFolderObserver;
1100 GObjectClass parent;
1101 } InternalFolderObserverClass;
1103 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1105 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1106 internal_folder_observer,
1108 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1112 foreach_add_item (gpointer header, gpointer user_data)
1114 tny_list_prepend (TNY_LIST (user_data),
1115 g_object_ref (G_OBJECT (header)));
1118 /* This is the method that looks for new messages in a folder */
1120 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1122 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1124 TnyFolderChangeChanged changed;
1126 changed = tny_folder_change_get_changed (change);
1128 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1131 /* Get added headers */
1132 list = tny_simple_list_new ();
1133 tny_folder_change_get_added_headers (change, list);
1135 /* Add them to the folder observer */
1136 tny_list_foreach (list, foreach_add_item,
1137 derived->new_headers);
1139 g_object_unref (G_OBJECT (list));
1144 internal_folder_observer_init (InternalFolderObserver *self)
1146 self->new_headers = tny_simple_list_new ();
1149 internal_folder_observer_finalize (GObject *object)
1151 InternalFolderObserver *self;
1153 self = (InternalFolderObserver *) object;
1154 g_object_unref (self->new_headers);
1156 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1159 tny_folder_observer_init (TnyFolderObserverIface *iface)
1161 iface->update = internal_folder_observer_update;
1164 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1166 GObjectClass *object_class;
1168 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1169 object_class = (GObjectClass*) klass;
1170 object_class->finalize = internal_folder_observer_finalize;
1175 ModestMailOperation *mail_op;
1176 gchar *account_name;
1177 UpdateAccountCallback callback;
1182 TnyFolderObserver *inbox_observer;
1183 RetrieveAllCallback retrieve_all_cb;
1184 gboolean interactive;
1185 } UpdateAccountInfo;
1189 destroy_update_account_info (UpdateAccountInfo *info)
1191 g_free (info->account_name);
1192 g_object_unref (info->folders);
1193 g_object_unref (info->mail_op);
1194 g_slice_free (UpdateAccountInfo, info);
1198 update_account_get_msg_async_cb (TnyFolder *folder,
1204 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1206 /* Just delete the helper. Don't do anything with the new
1207 msg. There is also no need to check for errors */
1208 g_object_unref (msg_info->mail_op);
1209 g_object_unref (msg_info->header);
1210 g_slice_free (GetMsgInfo, msg_info);
1214 inbox_refreshed_cb (TnyFolder *inbox,
1219 UpdateAccountInfo *info;
1220 ModestMailOperationPrivate *priv;
1221 TnyIterator *new_headers_iter;
1222 GPtrArray *new_headers_array = NULL;
1223 gint max_size, retrieve_limit, i;
1224 ModestAccountMgr *mgr;
1225 ModestAccountRetrieveType retrieve_type;
1226 TnyList *new_headers = NULL;
1227 gboolean headers_only, ignore_limit, succeeded;
1228 TnyTransportAccount *transport_account = NULL;
1230 info = (UpdateAccountInfo *) user_data;
1231 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1232 mgr = modest_runtime_get_account_mgr ();
1234 if (canceled || err || !inbox) {
1235 /* Try to send anyway */
1239 /* Get the message max size */
1240 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1241 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1243 max_size = G_MAXINT;
1245 max_size = max_size * KB;
1247 /* Create the new headers array. We need it to sort the
1248 new headers by date */
1249 new_headers_array = g_ptr_array_new ();
1250 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1251 while (!tny_iterator_is_done (new_headers_iter)) {
1252 TnyHeader *header = NULL;
1254 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1255 /* Apply per-message size limits */
1256 if (tny_header_get_message_size (header) < max_size)
1257 g_ptr_array_add (new_headers_array, g_object_ref (header));
1259 g_object_unref (header);
1260 tny_iterator_next (new_headers_iter);
1262 g_object_unref (new_headers_iter);
1263 tny_folder_remove_observer (inbox, info->inbox_observer);
1264 g_object_unref (info->inbox_observer);
1265 info->inbox_observer = NULL;
1267 /* Update the last updated key, even if we don't have to get new headers */
1268 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1269 if (!canceled && !err)
1270 modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
1272 if (new_headers_array->len == 0)
1275 /* Get per-account message amount retrieval limit */
1276 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1277 if (retrieve_limit == 0)
1278 retrieve_limit = G_MAXINT;
1280 /* Get per-account retrieval type */
1281 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1282 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1285 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1287 /* Ask the users if they want to retrieve all the messages
1288 even though the limit was exceeded */
1289 ignore_limit = FALSE;
1290 if (new_headers_array->len > retrieve_limit) {
1291 /* Ask the user if a callback has been specified and
1292 if the mail operation has a source (this means that
1293 was invoked by the user and not automatically by a
1295 if (info->retrieve_all_cb && priv->source)
1296 ignore_limit = info->retrieve_all_cb (priv->source,
1297 new_headers_array->len,
1301 if (!headers_only) {
1303 const gint msg_list_size = compute_message_array_size (new_headers_array);
1307 priv->total = new_headers_array->len;
1309 priv->total = MIN (new_headers_array->len, retrieve_limit);
1310 while (msg_num < priv->total) {
1311 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1312 TnyFolder *folder = tny_header_get_folder (header);
1313 GetMsgInfo *msg_info;
1315 /* Create the message info */
1316 msg_info = g_slice_new0 (GetMsgInfo);
1317 msg_info->mail_op = g_object_ref (info->mail_op);
1318 msg_info->header = g_object_ref (header);
1319 msg_info->total_bytes = msg_list_size;
1321 /* Get message in an async way */
1322 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1323 get_msg_status_cb, msg_info);
1325 g_object_unref (folder);
1331 /* Copy the headers to a list and free the array */
1332 new_headers = tny_simple_list_new ();
1333 for (i=0; i < new_headers_array->len; i++) {
1334 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1335 tny_list_append (new_headers, G_OBJECT (header));
1337 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1338 g_ptr_array_free (new_headers_array, FALSE);
1344 modest_account_mgr_set_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1345 tny_account_get_name (priv->account),
1348 /* Get the transport account */
1349 transport_account = (TnyTransportAccount *)
1350 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1351 info->account_name);
1353 if (transport_account) {
1354 ModestTnySendQueue *send_queue;
1358 send_queue = modest_runtime_get_send_queue (transport_account);
1359 g_object_unref (transport_account);
1361 /* Get outbox folder */
1362 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1363 if (outbox) { /* this could fail in some cases */
1364 num_messages = tny_folder_get_all_count (outbox);
1365 g_object_unref (outbox);
1367 g_warning ("%s: could not get outbox", __FUNCTION__);
1371 if (num_messages != 0) {
1372 /* Reenable suspended items */
1373 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1376 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1377 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1382 /* Check if the operation was a success */
1384 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1386 /* Set the account back to not busy */
1387 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1389 /* Call the user callback */
1391 info->callback (info->mail_op, new_headers, info->user_data);
1393 /* Notify about operation end */
1394 modest_mail_operation_notify_end (info->mail_op);
1398 g_object_unref (new_headers);
1399 destroy_update_account_info (info);
1403 recurse_folders_async_cb (TnyFolderStore *folder_store,
1409 UpdateAccountInfo *info;
1410 ModestMailOperationPrivate *priv;
1412 info = (UpdateAccountInfo *) user_data;
1413 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1415 if (err || canceled) {
1416 /* Try to continue anyway */
1417 } else if (info->poke_all) {
1418 /* We're not getting INBOX children if we don't want to poke all */
1419 TnyIterator *iter = tny_list_create_iterator (list);
1420 while (!tny_iterator_is_done (iter)) {
1421 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1422 TnyList *folders = tny_simple_list_new ();
1424 /* Add to the list of all folders */
1425 tny_list_append (info->folders, (GObject *) folder);
1427 /* Add pending call */
1428 info->pending_calls++;
1430 tny_folder_store_get_folders_async (folder, folders, NULL,
1431 recurse_folders_async_cb,
1434 g_object_unref (G_OBJECT (folder));
1436 tny_iterator_next (iter);
1438 g_object_unref (G_OBJECT (iter));
1439 g_object_unref (G_OBJECT (list));
1442 /* Remove my own pending call */
1443 info->pending_calls--;
1445 /* This means that we have all the folders */
1446 if (info->pending_calls == 0) {
1447 TnyIterator *iter_all_folders;
1448 TnyFolder *inbox = NULL;
1450 iter_all_folders = tny_list_create_iterator (info->folders);
1452 /* Do a poke status over all folders */
1453 while (!tny_iterator_is_done (iter_all_folders) &&
1454 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1455 TnyFolder *folder = NULL;
1457 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1459 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1460 /* Get a reference to the INBOX */
1461 inbox = g_object_ref (folder);
1463 /* Issue a poke status over the folder */
1465 tny_folder_poke_status (folder);
1468 /* Free and go to next */
1469 g_object_unref (folder);
1470 tny_iterator_next (iter_all_folders);
1472 g_object_unref (iter_all_folders);
1474 /* Refresh the INBOX */
1476 /* Refresh the folder. Our observer receives
1477 * the new emails during folder refreshes, so
1478 * we can use observer->new_headers
1480 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1481 tny_folder_add_observer (inbox, info->inbox_observer);
1483 /* Refresh the INBOX */
1484 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1485 g_object_unref (inbox);
1487 /* We could not perform the inbox refresh but
1488 we'll try to send mails anyway */
1489 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1495 modest_mail_operation_update_account (ModestMailOperation *self,
1496 const gchar *account_name,
1498 gboolean interactive,
1499 RetrieveAllCallback retrieve_all_cb,
1500 UpdateAccountCallback callback,
1503 UpdateAccountInfo *info = NULL;
1504 ModestMailOperationPrivate *priv = NULL;
1505 ModestTnyAccountStore *account_store = NULL;
1507 ModestMailOperationState *state;
1509 /* Init mail operation */
1510 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1513 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1514 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1516 /* Get the store account */
1517 account_store = modest_runtime_get_account_store ();
1519 modest_tny_account_store_get_server_account (account_store,
1521 TNY_ACCOUNT_TYPE_STORE);
1523 /* The above function could return NULL */
1524 if (!priv->account) {
1525 /* Check if the operation was a success */
1526 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1527 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1529 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1531 /* Call the user callback */
1533 callback (self, NULL, user_data);
1535 /* Notify about operation end */
1536 modest_mail_operation_notify_end (self);
1541 /* Create the helper object */
1542 info = g_slice_new0 (UpdateAccountInfo);
1543 info->pending_calls = 1;
1544 info->folders = tny_simple_list_new ();
1545 info->mail_op = g_object_ref (self);
1546 info->poke_all = poke_all;
1547 info->interactive = interactive;
1548 info->account_name = g_strdup (account_name);
1549 info->callback = callback;
1550 info->user_data = user_data;
1551 info->retrieve_all_cb = retrieve_all_cb;
1553 /* Set account busy */
1554 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1555 modest_mail_operation_notify_start (self);
1557 /* notify about the start of the operation */
1558 state = modest_mail_operation_clone_state (self);
1562 /* Start notifying progress */
1563 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1564 g_slice_free (ModestMailOperationState, state);
1566 /* Get all folders and continue in the callback */
1567 folders = tny_simple_list_new ();
1568 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1570 recurse_folders_async_cb,
1575 * Used to notify the queue from the main
1576 * loop. We call it inside an idle call to achieve that
1579 idle_notify_queue (gpointer data)
1581 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1583 gdk_threads_enter ();
1584 modest_mail_operation_notify_end (mail_op);
1585 gdk_threads_leave ();
1586 g_object_unref (mail_op);
1592 compare_headers_by_date (gconstpointer a,
1595 TnyHeader **header1, **header2;
1596 time_t sent1, sent2;
1598 header1 = (TnyHeader **) a;
1599 header2 = (TnyHeader **) b;
1601 sent1 = tny_header_get_date_sent (*header1);
1602 sent2 = tny_header_get_date_sent (*header2);
1604 /* We want the most recent ones (greater time_t) at the
1613 /* ******************************************************************* */
1614 /* ************************** STORE ACTIONS ************************* */
1615 /* ******************************************************************* */
1618 ModestMailOperation *mail_op;
1619 CreateFolderUserCallback callback;
1625 create_folder_cb (TnyFolderStore *parent_folder,
1627 TnyFolder *new_folder,
1631 ModestMailOperationPrivate *priv;
1632 CreateFolderInfo *info;
1634 info = (CreateFolderInfo *) user_data;
1635 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1637 if (canceled || err) {
1638 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1640 priv->error = g_error_copy (err);
1642 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1643 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1646 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1649 /* The user will unref the new_folder */
1651 info->callback (info->mail_op, parent_folder,
1652 new_folder, info->user_data);
1654 /* Notify about operation end */
1655 modest_mail_operation_notify_end (info->mail_op);
1658 g_object_unref (info->mail_op);
1659 g_slice_free (CreateFolderInfo, info);
1663 modest_mail_operation_create_folder (ModestMailOperation *self,
1664 TnyFolderStore *parent,
1666 CreateFolderUserCallback callback,
1669 ModestMailOperationPrivate *priv;
1671 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1672 g_return_if_fail (name);
1674 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1675 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1676 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1677 g_object_ref (parent) :
1678 modest_tny_folder_get_account (TNY_FOLDER (parent));
1680 /* Check for already existing folder */
1681 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1682 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1683 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1684 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1685 _CS("ckdg_ib_folder_already_exists"));
1689 if (TNY_IS_FOLDER (parent)) {
1690 /* Check folder rules */
1691 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1692 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1693 /* Set status failed and set an error */
1694 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1695 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1696 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1697 _("mail_in_ui_folder_create_error"));
1701 if (!strcmp (name, " ") || strchr (name, '/')) {
1702 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1703 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1704 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1705 _("mail_in_ui_folder_create_error"));
1709 CreateFolderInfo *info;
1711 info = g_slice_new0 (CreateFolderInfo);
1712 info->mail_op = g_object_ref (self);
1713 info->callback = callback;
1714 info->user_data = user_data;
1716 modest_mail_operation_notify_start (self);
1718 /* Create the folder */
1719 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1722 /* Call the user callback anyway */
1724 callback (self, parent, NULL, user_data);
1725 /* Notify about operation end */
1726 modest_mail_operation_notify_end (self);
1731 modest_mail_operation_remove_folder (ModestMailOperation *self,
1733 gboolean remove_to_trash)
1735 ModestMailOperationPrivate *priv;
1736 ModestTnyFolderRules rules;
1738 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1739 g_return_if_fail (TNY_IS_FOLDER (folder));
1741 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1743 /* Check folder rules */
1744 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1745 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1746 /* Set status failed and set an error */
1747 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1748 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1749 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1750 _("mail_in_ui_folder_delete_error"));
1754 /* Get the account */
1755 priv->account = modest_tny_folder_get_account (folder);
1756 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1758 /* Delete folder or move to trash */
1759 if (remove_to_trash) {
1760 TnyFolder *trash_folder = NULL;
1761 trash_folder = modest_tny_account_get_special_folder (priv->account,
1762 TNY_FOLDER_TYPE_TRASH);
1763 /* TODO: error_handling */
1765 modest_mail_operation_notify_start (self);
1766 modest_mail_operation_xfer_folder (self, folder,
1767 TNY_FOLDER_STORE (trash_folder),
1769 g_object_unref (trash_folder);
1771 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1774 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1776 modest_mail_operation_notify_start (self);
1777 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1778 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1781 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1783 g_object_unref (parent);
1785 g_warning ("%s: could not get parent folder", __FUNCTION__);
1789 /* Notify about operation end */
1790 modest_mail_operation_notify_end (self);
1794 transfer_folder_status_cb (GObject *obj,
1798 ModestMailOperation *self;
1799 ModestMailOperationPrivate *priv;
1800 ModestMailOperationState *state;
1801 XFerFolderAsyncHelper *helper;
1803 g_return_if_fail (status != NULL);
1804 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1806 helper = (XFerFolderAsyncHelper *) user_data;
1807 g_return_if_fail (helper != NULL);
1809 self = helper->mail_op;
1810 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1812 priv->done = status->position;
1813 priv->total = status->of_total;
1815 state = modest_mail_operation_clone_state (self);
1817 /* This is not a GDK lock because we are a Tinymail callback
1818 * which is already GDK locked by Tinymail */
1820 /* no gdk_threads_enter (), CHECKED */
1822 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1824 /* no gdk_threads_leave (), CHECKED */
1826 g_slice_free (ModestMailOperationState, state);
1831 transfer_folder_cb (TnyFolder *folder,
1833 TnyFolderStore *into,
1834 TnyFolder *new_folder,
1838 XFerFolderAsyncHelper *helper;
1839 ModestMailOperation *self = NULL;
1840 ModestMailOperationPrivate *priv = NULL;
1842 helper = (XFerFolderAsyncHelper *) user_data;
1843 g_return_if_fail (helper != NULL);
1845 self = helper->mail_op;
1846 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1849 priv->error = g_error_copy (err);
1851 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1852 } else if (cancelled) {
1853 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1854 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1855 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1856 _("Transference of %s was cancelled."),
1857 tny_folder_get_name (folder));
1860 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1863 /* Notify about operation end */
1864 modest_mail_operation_notify_end (self);
1866 /* If user defined callback function was defined, call it */
1867 if (helper->user_callback) {
1869 /* This is not a GDK lock because we are a Tinymail callback
1870 * which is already GDK locked by Tinymail */
1872 /* no gdk_threads_enter (), CHECKED */
1873 helper->user_callback (self, new_folder, helper->user_data);
1874 /* no gdk_threads_leave () , CHECKED */
1878 g_object_unref (helper->mail_op);
1879 g_slice_free (XFerFolderAsyncHelper, helper);
1884 * This function checks if the new name is a valid name for our local
1885 * folders account. The new name could not be the same than then name
1886 * of any of the mandatory local folders
1888 * We can not rely on tinymail because tinymail does not check the
1889 * name of the virtual folders that the account could have in the case
1890 * that we're doing a rename (because it directly calls Camel which
1891 * knows nothing about our virtual folders).
1893 * In the case of an actual copy/move (i.e. move/copy a folder between
1894 * accounts) tinymail uses the tny_folder_store_create_account which
1895 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1896 * checks the new name of the folder, so this call in that case
1897 * wouldn't be needed. *But* NOTE that if tinymail changes its
1898 * implementation (if folder transfers within the same account is no
1899 * longer implemented as a rename) this call will allow Modest to work
1902 * If the new name is not valid, this function will set the status to
1903 * failed and will set also an error in the mail operation
1906 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1907 TnyFolderStore *into,
1908 const gchar *new_name)
1910 if (TNY_IS_ACCOUNT (into) &&
1911 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1912 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1914 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1915 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1916 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1917 _CS("ckdg_ib_folder_already_exists"));
1924 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1926 TnyFolderStore *parent,
1927 gboolean delete_original,
1928 XferFolderAsyncUserCallback user_callback,
1931 ModestMailOperationPrivate *priv = NULL;
1932 ModestTnyFolderRules parent_rules = 0, rules;
1933 XFerFolderAsyncHelper *helper = NULL;
1934 const gchar *folder_name = NULL;
1935 const gchar *error_msg;
1937 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1938 g_return_if_fail (TNY_IS_FOLDER (folder));
1939 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1941 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1942 folder_name = tny_folder_get_name (folder);
1944 /* Set the error msg */
1945 error_msg = _("mail_in_ui_folder_move_target_error");
1947 /* Get account and set it into mail_operation */
1948 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1949 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1950 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1952 /* Get folder rules */
1953 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1954 if (TNY_IS_FOLDER (parent))
1955 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1957 /* Apply operation constraints */
1958 if ((gpointer) parent == (gpointer) folder ||
1959 (!TNY_IS_FOLDER_STORE (parent)) ||
1960 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1963 } else if (TNY_IS_FOLDER (parent) &&
1964 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1968 } else if (TNY_IS_FOLDER (parent) &&
1969 TNY_IS_FOLDER_STORE (folder) &&
1970 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1971 TNY_FOLDER_STORE (folder))) {
1972 /* Do not move a parent into a child */
1974 } else if (TNY_IS_FOLDER_STORE (parent) &&
1975 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1976 /* Check that the new folder name is not used by any
1979 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1980 /* Check that the new folder name is not used by any
1981 special local folder */
1984 /* Create the helper */
1985 helper = g_slice_new0 (XFerFolderAsyncHelper);
1986 helper->mail_op = g_object_ref (self);
1987 helper->user_callback = user_callback;
1988 helper->user_data = user_data;
1990 /* Move/Copy folder */
1991 modest_mail_operation_notify_start (self);
1992 tny_folder_copy_async (folder,
1994 tny_folder_get_name (folder),
1997 transfer_folder_status_cb,
2003 /* Set status failed and set an error */
2004 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2005 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2006 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2009 /* Call the user callback if exists */
2011 user_callback (self, NULL, user_data);
2013 /* Notify the queue */
2014 modest_mail_operation_notify_end (self);
2018 modest_mail_operation_rename_folder (ModestMailOperation *self,
2021 XferFolderAsyncUserCallback user_callback,
2024 ModestMailOperationPrivate *priv;
2025 ModestTnyFolderRules rules;
2026 XFerFolderAsyncHelper *helper;
2028 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2029 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2030 g_return_if_fail (name);
2032 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2034 /* Get account and set it into mail_operation */
2035 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2036 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2038 /* Check folder rules */
2039 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2040 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2042 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2045 TnyFolderStore *into;
2047 into = tny_folder_get_folder_store (folder);
2049 /* Check that the new folder name is not used by any
2050 special local folder */
2051 if (new_name_valid_if_local_account (priv, into, name)) {
2052 /* Create the helper */
2053 helper = g_slice_new0 (XFerFolderAsyncHelper);
2054 helper->mail_op = g_object_ref(self);
2055 helper->user_callback = user_callback;
2056 helper->user_data = user_data;
2058 /* Rename. Camel handles folder subscription/unsubscription */
2059 modest_mail_operation_notify_start (self);
2060 tny_folder_copy_async (folder, into, name, TRUE,
2062 transfer_folder_status_cb,
2067 g_object_unref (into);
2072 /* Set status failed and set an error */
2073 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2074 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2075 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2076 _("FIXME: unable to rename"));
2079 user_callback (self, NULL, user_data);
2081 /* Notify about operation end */
2082 modest_mail_operation_notify_end (self);
2085 /* ******************************************************************* */
2086 /* ************************** MSG ACTIONS ************************* */
2087 /* ******************************************************************* */
2090 modest_mail_operation_get_msg (ModestMailOperation *self,
2092 GetMsgAsyncUserCallback user_callback,
2095 GetMsgInfo *helper = NULL;
2097 ModestMailOperationPrivate *priv;
2099 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2100 g_return_if_fail (TNY_IS_HEADER (header));
2102 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2103 folder = tny_header_get_folder (header);
2105 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2109 /* Get account and set it into mail_operation */
2110 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2112 /* Check for cached messages */
2113 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2114 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2116 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2118 /* Create the helper */
2119 helper = g_slice_new0 (GetMsgInfo);
2120 helper->header = g_object_ref (header);
2121 helper->mail_op = g_object_ref (self);
2122 helper->user_callback = user_callback;
2123 helper->user_data = user_data;
2124 helper->destroy_notify = NULL;
2125 helper->last_total_bytes = 0;
2126 helper->sum_total_bytes = 0;
2127 helper->total_bytes = tny_header_get_message_size (header);
2129 modest_mail_operation_notify_start (self);
2131 /* notify about the start of the operation */
2132 ModestMailOperationState *state;
2133 state = modest_mail_operation_clone_state (self);
2136 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2139 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2141 g_object_unref (G_OBJECT (folder));
2145 get_msg_status_cb (GObject *obj,
2149 GetMsgInfo *helper = NULL;
2151 g_return_if_fail (status != NULL);
2152 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2154 helper = (GetMsgInfo *) user_data;
2155 g_return_if_fail (helper != NULL);
2157 /* Notify progress */
2158 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2159 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2163 get_msg_async_cb (TnyFolder *folder,
2169 GetMsgInfo *info = NULL;
2170 ModestMailOperationPrivate *priv = NULL;
2173 info = (GetMsgInfo *) user_data;
2175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2178 if (info->more_msgs) {
2179 tny_iterator_next (info->more_msgs);
2180 finished = (tny_iterator_is_done (info->more_msgs));
2182 finished = (priv->done == priv->total) ? TRUE : FALSE;
2185 /* If canceled by the user, ignore the error given by Tinymail */
2186 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2189 } else if (canceled || err) {
2190 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2192 priv->error = g_error_copy ((const GError *) err);
2193 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2196 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2197 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2200 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2201 /* Set the success status before calling the user callback */
2202 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2206 /* Call the user callback */
2207 if (info->user_callback)
2208 info->user_callback (info->mail_op, info->header, canceled,
2209 msg, err, info->user_data);
2211 /* Notify about operation end if this is the last callback */
2213 /* Free user data */
2214 if (info->destroy_notify)
2215 info->destroy_notify (info->user_data);
2217 /* Notify about operation end */
2218 modest_mail_operation_notify_end (info->mail_op);
2221 if (info->more_msgs)
2222 g_object_unref (info->more_msgs);
2223 g_object_unref (info->header);
2224 g_object_unref (info->mail_op);
2225 g_slice_free (GetMsgInfo, info);
2226 } else if (info->more_msgs) {
2227 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2228 TnyFolder *folder = tny_header_get_folder (header);
2230 g_object_unref (info->header);
2231 info->header = g_object_ref (header);
2233 /* Retrieve the next message */
2234 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2236 g_object_unref (header);
2237 g_object_unref (folder);
2239 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2244 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2245 TnyList *header_list,
2246 GetMsgAsyncUserCallback user_callback,
2248 GDestroyNotify notify)
2250 ModestMailOperationPrivate *priv = NULL;
2252 TnyIterator *iter = NULL;
2253 gboolean has_uncached_messages;
2255 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2257 /* Init mail operation */
2258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2259 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2261 priv->total = tny_list_get_length(header_list);
2263 /* Check uncached messages */
2264 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2265 !has_uncached_messages && !tny_iterator_is_done (iter);
2266 tny_iterator_next (iter)) {
2269 header = (TnyHeader *) tny_iterator_get_current (iter);
2270 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2271 has_uncached_messages = TRUE;
2272 g_object_unref (header);
2274 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2276 /* Get account and set it into mail_operation */
2277 if (tny_list_get_length (header_list) >= 1) {
2278 TnyIterator *iterator = tny_list_create_iterator (header_list);
2279 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2281 TnyFolder *folder = tny_header_get_folder (header);
2283 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2284 g_object_unref (folder);
2286 g_object_unref (header);
2288 g_object_unref (iterator);
2291 msg_list_size = compute_message_list_size (header_list);
2293 modest_mail_operation_notify_start (self);
2294 iter = tny_list_create_iterator (header_list);
2295 if (!tny_iterator_is_done (iter)) {
2296 /* notify about the start of the operation */
2297 ModestMailOperationState *state;
2298 state = modest_mail_operation_clone_state (self);
2301 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2304 GetMsgInfo *msg_info = NULL;
2305 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2306 TnyFolder *folder = tny_header_get_folder (header);
2308 /* Create the message info */
2309 msg_info = g_slice_new0 (GetMsgInfo);
2310 msg_info->mail_op = g_object_ref (self);
2311 msg_info->header = g_object_ref (header);
2312 msg_info->more_msgs = g_object_ref (iter);
2313 msg_info->user_callback = user_callback;
2314 msg_info->user_data = user_data;
2315 msg_info->destroy_notify = notify;
2316 msg_info->last_total_bytes = 0;
2317 msg_info->sum_total_bytes = 0;
2318 msg_info->total_bytes = msg_list_size;
2320 /* The callback will call it per each header */
2321 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2323 /* Free and go on */
2324 g_object_unref (header);
2325 g_object_unref (folder);
2326 g_slice_free (ModestMailOperationState, state);
2328 g_object_unref (iter);
2333 modest_mail_operation_remove_msg (ModestMailOperation *self,
2335 gboolean remove_to_trash /*ignored*/)
2338 ModestMailOperationPrivate *priv;
2340 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2341 g_return_if_fail (TNY_IS_HEADER (header));
2343 if (remove_to_trash)
2344 g_warning ("remove to trash is not implemented");
2346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2347 folder = tny_header_get_folder (header);
2349 /* Get account and set it into mail_operation */
2350 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2351 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2352 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2354 /* remove message from folder */
2355 tny_folder_remove_msg (folder, header, &(priv->error));
2357 gboolean expunge, leave_on_server;
2358 const gchar *account_name;
2359 TnyAccount *account;
2360 ModestTransportStoreProtocol account_proto;
2362 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2363 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2365 modest_mail_operation_notify_start (self);
2367 /* Get leave on server setting */
2368 account = tny_folder_get_account (folder);
2369 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2371 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2374 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2376 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2377 modest_tny_folder_is_remote_folder (folder) == FALSE)
2383 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2386 g_object_unref (account);
2392 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2394 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2397 g_object_unref (G_OBJECT (folder));
2399 /* Notify about operation end */
2400 modest_mail_operation_notify_end (self);
2404 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2406 gboolean remove_to_trash /*ignored*/)
2408 TnyFolder *folder = NULL;
2409 ModestMailOperationPrivate *priv;
2410 TnyIterator *iter = NULL;
2411 TnyHeader *header = NULL;
2412 TnyList *remove_headers = NULL;
2413 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2415 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2416 g_return_if_fail (TNY_IS_LIST (headers));
2418 if (remove_to_trash)
2419 g_warning ("remove to trash is not implemented");
2421 if (tny_list_get_length(headers) == 0) {
2422 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2423 goto cleanup; /* nothing to do */
2426 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2427 remove_headers = g_object_ref(headers);
2429 /* Get folder from first header and sync it */
2430 iter = tny_list_create_iterator (headers);
2431 header = TNY_HEADER (tny_iterator_get_current (iter));
2433 folder = tny_header_get_folder (header);
2434 if (!TNY_IS_FOLDER(folder)) {
2435 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2439 /* Don't remove messages that are being sent */
2440 if (modest_tny_folder_is_local_folder (folder)) {
2441 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2443 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2444 TnyTransportAccount *traccount = NULL;
2445 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2446 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2448 ModestTnySendQueueStatus status;
2449 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2450 TnyIterator *iter = tny_list_create_iterator(headers);
2451 g_object_unref(remove_headers);
2452 remove_headers = TNY_LIST(tny_simple_list_new());
2453 while (!tny_iterator_is_done(iter)) {
2455 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2456 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2457 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2458 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2459 tny_list_append(remove_headers, G_OBJECT(hdr));
2461 g_object_unref(hdr);
2463 tny_iterator_next(iter);
2465 g_object_unref(iter);
2466 g_object_unref(traccount);
2470 /* Get account and set it into mail_operation */
2471 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2472 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2473 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2475 /* remove message from folder */
2476 modest_mail_operation_notify_start (self);
2478 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2480 gboolean expunge, leave_on_server;
2481 const gchar *account_name;
2483 TnyAccount *account;
2484 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2486 account = tny_folder_get_account (folder);
2487 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2489 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2492 proto = tny_account_get_proto (account);
2494 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2497 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2498 modest_tny_folder_is_remote_folder (folder) == FALSE)
2504 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2506 g_object_unref (account);
2512 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2514 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2519 g_object_unref (remove_headers);
2521 g_object_unref (header);
2523 g_object_unref (iter);
2525 g_object_unref (folder);
2527 /* Notify about operation end */
2528 modest_mail_operation_notify_end (self);
2532 notify_progress_of_multiple_messages (ModestMailOperation *self,
2534 gint *last_total_bytes,
2535 gint *sum_total_bytes,
2537 gboolean increment_done)
2539 ModestMailOperationPrivate *priv;
2540 ModestMailOperationState *state;
2541 gboolean is_num_bytes = FALSE;
2543 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2545 /* We know that tinymail sends us information about
2546 * transferred bytes with this particular message
2548 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2549 * I just added the 'if' so we don't get runtime warning)
2551 if (status->message)
2552 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2554 state = modest_mail_operation_clone_state (self);
2555 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2556 /* We know that we're in a different message when the
2557 total number of bytes to transfer is different. Of
2558 course it could fail if we're transferring messages
2559 of the same size, but this is a workarround */
2560 if (status->of_total != *last_total_bytes) {
2561 /* We need to increment the done when there is
2562 no information about each individual
2563 message, we need to do this in message
2564 transfers, and we don't do it for getting
2568 *sum_total_bytes += *last_total_bytes;
2569 *last_total_bytes = status->of_total;
2571 state->bytes_done += status->position + *sum_total_bytes;
2572 state->bytes_total = total_bytes;
2574 /* Notify the status change. Only notify about changes
2575 referred to bytes */
2576 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2580 g_slice_free (ModestMailOperationState, state);
2584 transfer_msgs_status_cb (GObject *obj,
2588 XFerMsgsAsyncHelper *helper;
2590 g_return_if_fail (status != NULL);
2591 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2593 helper = (XFerMsgsAsyncHelper *) user_data;
2594 g_return_if_fail (helper != NULL);
2596 /* Notify progress */
2597 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2598 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2603 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2605 XFerMsgsAsyncHelper *helper;
2606 ModestMailOperation *self;
2607 ModestMailOperationPrivate *priv;
2608 gboolean finished = TRUE;
2610 helper = (XFerMsgsAsyncHelper *) user_data;
2611 self = helper->mail_op;
2613 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2616 priv->error = g_error_copy (err);
2618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2619 } else if (cancelled) {
2620 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2621 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2622 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2623 _("Error trying to refresh the contents of %s"),
2624 tny_folder_get_name (folder));
2625 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2626 if (helper->more_msgs) {
2627 /* We'll transfer the next message in the list */
2628 tny_iterator_next (helper->more_msgs);
2629 if (!tny_iterator_is_done (helper->more_msgs)) {
2630 GObject *next_header;
2631 g_object_unref (helper->headers);
2632 helper->headers = tny_simple_list_new ();
2633 next_header = tny_iterator_get_current (helper->more_msgs);
2634 tny_list_append (helper->headers, next_header);
2635 g_object_unref (next_header);
2642 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2648 /* Update folder counts */
2649 tny_folder_poke_status (folder);
2650 tny_folder_poke_status (helper->dest_folder);
2652 /* Notify about operation end */
2653 modest_mail_operation_notify_end (self);
2655 /* If user defined callback function was defined, call it */
2656 if (helper->user_callback) {
2657 /* This is not a GDK lock because we are a Tinymail callback and
2658 * Tinymail already acquires the Gdk lock */
2660 /* no gdk_threads_enter (), CHECKED */
2661 helper->user_callback (self, helper->user_data);
2662 /* no gdk_threads_leave (), CHECKED */
2666 if (helper->more_msgs)
2667 g_object_unref (helper->more_msgs);
2668 if (helper->headers)
2669 g_object_unref (helper->headers);
2670 if (helper->dest_folder)
2671 g_object_unref (helper->dest_folder);
2672 if (helper->mail_op)
2673 g_object_unref (helper->mail_op);
2674 g_slice_free (XFerMsgsAsyncHelper, helper);
2676 /* Transfer more messages */
2677 tny_folder_transfer_msgs_async (folder,
2679 helper->dest_folder,
2682 transfer_msgs_status_cb,
2688 compute_message_list_size (TnyList *headers)
2693 iter = tny_list_create_iterator (headers);
2694 while (!tny_iterator_is_done (iter)) {
2695 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2696 size += tny_header_get_message_size (header);
2697 g_object_unref (header);
2698 tny_iterator_next (iter);
2700 g_object_unref (iter);
2706 compute_message_array_size (GPtrArray *headers)
2711 for (i = 0; i < headers->len; i++) {
2712 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2713 size += tny_header_get_message_size (header);
2721 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2724 gboolean delete_original,
2725 XferMsgsAsyncUserCallback user_callback,
2728 ModestMailOperationPrivate *priv = NULL;
2729 TnyIterator *iter = NULL;
2730 TnyFolder *src_folder = NULL;
2731 XFerMsgsAsyncHelper *helper = NULL;
2732 TnyHeader *header = NULL;
2733 ModestTnyFolderRules rules = 0;
2734 TnyAccount *dst_account = NULL;
2735 gboolean leave_on_server;
2737 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2738 g_return_if_fail (headers && TNY_IS_LIST (headers));
2739 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2741 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2742 priv->total = tny_list_get_length (headers);
2744 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2745 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2747 /* Apply folder rules */
2748 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2749 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2750 /* Set status failed and set an error */
2751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2752 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2753 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2754 _CS("ckct_ib_unable_to_paste_here"));
2755 /* Notify the queue */
2756 modest_mail_operation_notify_end (self);
2760 /* Get source folder */
2761 iter = tny_list_create_iterator (headers);
2762 header = TNY_HEADER (tny_iterator_get_current (iter));
2764 src_folder = tny_header_get_folder (header);
2765 g_object_unref (header);
2767 g_object_unref (iter);
2769 if (src_folder == NULL) {
2770 /* Notify the queue */
2771 modest_mail_operation_notify_end (self);
2773 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2778 /* Check folder source and destination */
2779 if (src_folder == folder) {
2780 /* Set status failed and set an error */
2781 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2782 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2783 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2784 _("mail_in_ui_folder_copy_target_error"));
2786 /* Notify the queue */
2787 modest_mail_operation_notify_end (self);
2790 g_object_unref (src_folder);
2794 /* Create the helper */
2795 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2796 helper->mail_op = g_object_ref(self);
2797 helper->dest_folder = g_object_ref(folder);
2798 helper->user_callback = user_callback;
2799 helper->user_data = user_data;
2800 helper->delete = delete_original;
2801 helper->last_total_bytes = 0;
2802 helper->sum_total_bytes = 0;
2803 helper->total_bytes = compute_message_list_size (headers);
2805 /* Get account and set it into mail_operation */
2806 priv->account = modest_tny_folder_get_account (src_folder);
2807 dst_account = modest_tny_folder_get_account (folder);
2809 if (priv->account == dst_account) {
2810 /* Transfer all messages at once using the fast
2811 * method. Note that depending on the server this
2812 * might not be that fast, and might not be
2813 * user-cancellable either */
2814 helper->headers = g_object_ref (headers);
2815 helper->more_msgs = NULL;
2817 /* Transfer messages one by one so the user can cancel
2820 helper->headers = tny_simple_list_new ();
2821 helper->more_msgs = tny_list_create_iterator (headers);
2822 hdr = tny_iterator_get_current (helper->more_msgs);
2823 tny_list_append (helper->headers, hdr);
2824 g_object_unref (hdr);
2827 /* If leave_on_server is set to TRUE then don't use
2828 delete_original, we always pass FALSE. This is because
2829 otherwise tinymail will try to sync the source folder and
2830 this could cause an error if we're offline while
2831 transferring an already downloaded message from a POP
2833 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2834 MODEST_PROTOCOL_STORE_POP) {
2835 const gchar *account_name;
2837 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2838 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2841 leave_on_server = FALSE;
2844 modest_mail_operation_notify_start (self);
2845 tny_folder_transfer_msgs_async (src_folder,
2848 (leave_on_server) ? FALSE : delete_original,
2850 transfer_msgs_status_cb,
2852 g_object_unref (src_folder);
2853 g_object_unref (dst_account);
2858 on_refresh_folder (TnyFolder *folder,
2863 RefreshAsyncHelper *helper = NULL;
2864 ModestMailOperation *self = NULL;
2865 ModestMailOperationPrivate *priv = NULL;
2867 helper = (RefreshAsyncHelper *) user_data;
2868 self = helper->mail_op;
2869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2871 g_return_if_fail(priv!=NULL);
2874 priv->error = g_error_copy (error);
2875 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2880 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2881 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2882 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2883 _("Error trying to refresh the contents of %s"),
2884 tny_folder_get_name (folder));
2888 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2891 /* Call user defined callback, if it exists */
2892 if (helper->user_callback) {
2894 /* This is not a GDK lock because we are a Tinymail callback and
2895 * Tinymail already acquires the Gdk lock */
2896 helper->user_callback (self, folder, helper->user_data);
2900 g_slice_free (RefreshAsyncHelper, helper);
2902 /* Notify about operation end */
2903 modest_mail_operation_notify_end (self);
2904 g_object_unref(self);
2908 on_refresh_folder_status_update (GObject *obj,
2912 RefreshAsyncHelper *helper = NULL;
2913 ModestMailOperation *self = NULL;
2914 ModestMailOperationPrivate *priv = NULL;
2915 ModestMailOperationState *state;
2917 g_return_if_fail (user_data != NULL);
2918 g_return_if_fail (status != NULL);
2919 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2921 helper = (RefreshAsyncHelper *) user_data;
2922 self = helper->mail_op;
2923 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2925 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2927 priv->done = status->position;
2928 priv->total = status->of_total;
2930 state = modest_mail_operation_clone_state (self);
2932 /* This is not a GDK lock because we are a Tinymail callback and
2933 * Tinymail already acquires the Gdk lock */
2934 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2936 g_slice_free (ModestMailOperationState, state);
2940 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2942 RefreshAsyncUserCallback user_callback,
2945 ModestMailOperationPrivate *priv = NULL;
2946 RefreshAsyncHelper *helper = NULL;
2948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2950 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2952 /* Get account and set it into mail_operation */
2953 priv->account = modest_tny_folder_get_account (folder);
2954 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2956 /* Create the helper */
2957 helper = g_slice_new0 (RefreshAsyncHelper);
2958 helper->mail_op = g_object_ref(self);
2959 helper->user_callback = user_callback;
2960 helper->user_data = user_data;
2962 modest_mail_operation_notify_start (self);
2964 /* notify that the operation was started */
2965 ModestMailOperationState *state;
2966 state = modest_mail_operation_clone_state (self);
2969 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2972 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2974 tny_folder_refresh_async (folder,
2976 on_refresh_folder_status_update,
2981 run_queue_stop (ModestTnySendQueue *queue,
2982 ModestMailOperation *self)
2984 ModestMailOperationPrivate *priv;
2986 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2987 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2988 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2990 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2992 modest_mail_operation_notify_end (self);
2993 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
2994 g_object_unref (self);
2997 modest_mail_operation_run_queue (ModestMailOperation *self,
2998 ModestTnySendQueue *queue)
3000 ModestMailOperationPrivate *priv;
3002 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3003 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3004 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3006 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3007 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3008 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3010 modest_mail_operation_notify_start (self);
3011 g_object_ref (self);
3012 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3016 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3018 ModestMailOperationPrivate *priv;
3020 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3022 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3023 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3025 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3027 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3029 modest_mail_operation_notify_end (mail_op);
3030 g_object_unref (mail_op);
3034 modest_mail_operation_sync_folder (ModestMailOperation *self,
3035 TnyFolder *folder, gboolean expunge)
3037 ModestMailOperationPrivate *priv;
3039 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3040 g_return_if_fail (TNY_IS_FOLDER (folder));
3041 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3043 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3044 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3045 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3047 modest_mail_operation_notify_start (self);
3048 g_object_ref (self);
3049 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3053 modest_mail_operation_notify_start (ModestMailOperation *self)
3055 ModestMailOperationPrivate *priv = NULL;
3057 g_return_if_fail (self);
3059 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3061 /* Ensure that all the fields are filled correctly */
3062 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3064 /* Notify the observers about the mail operation. We do not
3065 wrapp this emission because we assume that this function is
3066 always called from within the main lock */
3067 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3072 * It's used by the mail operation queue to notify the observers
3073 * attached to that signal that the operation finished. We need to use
3074 * that because tinymail does not give us the progress of a given
3075 * operation when it finishes (it directly calls the operation
3079 modest_mail_operation_notify_end (ModestMailOperation *self)
3081 ModestMailOperationPrivate *priv = NULL;
3083 g_return_if_fail (self);
3085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3087 /* Notify the observers about the mail operation end. We do
3088 not wrapp this emission because we assume that this
3089 function is always called from within the main lock */
3090 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3092 /* Remove the error user data */
3093 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3094 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3098 modest_mail_operation_get_account (ModestMailOperation *self)
3100 ModestMailOperationPrivate *priv = NULL;
3102 g_return_val_if_fail (self, NULL);
3104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3106 return (priv->account) ? g_object_ref (priv->account) : NULL;
3110 modest_mail_operation_noop (ModestMailOperation *self)
3112 ModestMailOperationPrivate *priv = NULL;
3114 g_return_if_fail (self);
3116 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3117 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3118 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3122 /* This mail operation does nothing actually */
3123 modest_mail_operation_notify_start (self);
3124 modest_mail_operation_notify_end (self);
3129 modest_mail_operation_to_string (ModestMailOperation *self)
3131 const gchar *type, *status, *account_id;
3132 ModestMailOperationPrivate *priv = NULL;
3134 g_return_val_if_fail (self, NULL);
3136 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3138 /* new operations don't have anything interesting */
3139 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3140 return g_strdup_printf ("%p <new operation>", self);
3142 switch (priv->op_type) {
3143 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3144 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3145 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3146 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3147 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3148 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3149 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3150 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3151 default: type = "UNEXPECTED"; break;
3154 switch (priv->status) {
3155 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3156 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3157 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3158 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3159 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3160 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3161 default: status= "UNEXPECTED"; break;
3164 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3166 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3167 priv->done, priv->total,
3168 priv->error && priv->error->message ? priv->error->message : "");