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 update_account_notify_user_and_free (UpdateAccountInfo *info,
1215 TnyList *new_headers)
1217 /* Set the account back to not busy */
1218 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1219 info->account_name, FALSE);
1223 info->callback (info->mail_op, new_headers, info->user_data);
1225 /* Mail operation end */
1226 modest_mail_operation_notify_end (info->mail_op);
1230 g_object_unref (new_headers);
1231 destroy_update_account_info (info);
1235 inbox_refreshed_cb (TnyFolder *inbox,
1240 UpdateAccountInfo *info;
1241 ModestMailOperationPrivate *priv;
1242 TnyIterator *new_headers_iter;
1243 GPtrArray *new_headers_array = NULL;
1244 gint max_size, retrieve_limit, i;
1245 ModestAccountMgr *mgr;
1246 ModestAccountRetrieveType retrieve_type;
1247 TnyList *new_headers = NULL;
1248 gboolean headers_only, ignore_limit, succeeded;
1249 TnyTransportAccount *transport_account = NULL;
1251 info = (UpdateAccountInfo *) user_data;
1252 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1253 mgr = modest_runtime_get_account_mgr ();
1255 if (canceled || err) {
1256 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1258 priv->error = g_error_copy (err);
1260 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1261 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1263 /* Notify the user about the error and then exit */
1264 update_account_notify_user_and_free (info, NULL);
1269 /* Try to send anyway */
1273 /* Get the message max size */
1274 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1275 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1277 max_size = G_MAXINT;
1279 max_size = max_size * KB;
1281 /* Create the new headers array. We need it to sort the
1282 new headers by date */
1283 new_headers_array = g_ptr_array_new ();
1284 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1285 while (!tny_iterator_is_done (new_headers_iter)) {
1286 TnyHeader *header = NULL;
1288 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1289 /* Apply per-message size limits */
1290 if (tny_header_get_message_size (header) < max_size)
1291 g_ptr_array_add (new_headers_array, g_object_ref (header));
1293 g_object_unref (header);
1294 tny_iterator_next (new_headers_iter);
1296 g_object_unref (new_headers_iter);
1297 tny_folder_remove_observer (inbox, info->inbox_observer);
1298 g_object_unref (info->inbox_observer);
1299 info->inbox_observer = NULL;
1301 /* Update the last updated key, even if we don't have to get new headers */
1302 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1303 if (!canceled && !err)
1304 modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
1306 if (new_headers_array->len == 0)
1309 /* Get per-account message amount retrieval limit */
1310 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1311 if (retrieve_limit == 0)
1312 retrieve_limit = G_MAXINT;
1314 /* Get per-account retrieval type */
1315 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1316 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1319 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1321 /* Ask the users if they want to retrieve all the messages
1322 even though the limit was exceeded */
1323 ignore_limit = FALSE;
1324 if (new_headers_array->len > retrieve_limit) {
1325 /* Ask the user if a callback has been specified and
1326 if the mail operation has a source (this means that
1327 was invoked by the user and not automatically by a
1329 if (info->retrieve_all_cb && priv->source)
1330 ignore_limit = info->retrieve_all_cb (priv->source,
1331 new_headers_array->len,
1335 if (!headers_only) {
1337 const gint msg_list_size = compute_message_array_size (new_headers_array);
1341 priv->total = new_headers_array->len;
1343 priv->total = MIN (new_headers_array->len, retrieve_limit);
1344 while (msg_num < priv->total) {
1345 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1346 TnyFolder *folder = tny_header_get_folder (header);
1347 GetMsgInfo *msg_info;
1349 /* Create the message info */
1350 msg_info = g_slice_new0 (GetMsgInfo);
1351 msg_info->mail_op = g_object_ref (info->mail_op);
1352 msg_info->header = g_object_ref (header);
1353 msg_info->total_bytes = msg_list_size;
1355 /* Get message in an async way */
1356 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1357 get_msg_status_cb, msg_info);
1359 g_object_unref (folder);
1365 /* Copy the headers to a list and free the array */
1366 new_headers = tny_simple_list_new ();
1367 for (i=0; i < new_headers_array->len; i++) {
1368 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1369 tny_list_append (new_headers, G_OBJECT (header));
1371 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1372 g_ptr_array_free (new_headers_array, FALSE);
1378 modest_account_mgr_set_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1379 tny_account_get_name (priv->account),
1382 /* Get the transport account */
1383 transport_account = (TnyTransportAccount *)
1384 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1385 info->account_name);
1387 if (transport_account) {
1388 ModestTnySendQueue *send_queue;
1392 send_queue = modest_runtime_get_send_queue (transport_account);
1393 g_object_unref (transport_account);
1395 /* Get outbox folder */
1396 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1397 if (outbox) { /* this could fail in some cases */
1398 num_messages = tny_folder_get_all_count (outbox);
1399 g_object_unref (outbox);
1401 g_warning ("%s: could not get outbox", __FUNCTION__);
1405 if (num_messages != 0) {
1406 /* Reenable suspended items */
1407 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1410 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1411 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1416 /* Check if the operation was a success */
1418 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1420 /* Call the user callback and free */
1421 update_account_notify_user_and_free (info, new_headers);
1425 recurse_folders_async_cb (TnyFolderStore *folder_store,
1431 UpdateAccountInfo *info;
1432 ModestMailOperationPrivate *priv;
1434 info = (UpdateAccountInfo *) user_data;
1435 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1437 if (err || canceled) {
1438 /* If the error was previosly set by another callback
1439 don't set it again */
1441 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1443 priv->error = g_error_copy (err);
1445 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1446 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1450 /* We're not getting INBOX children if we don't want to poke all */
1451 TnyIterator *iter = tny_list_create_iterator (list);
1452 while (!tny_iterator_is_done (iter)) {
1453 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1455 /* Add to the list of all folders */
1456 tny_list_append (info->folders, (GObject *) folder);
1458 if (info->poke_all) {
1459 TnyList *folders = tny_simple_list_new ();
1460 /* Add pending call */
1461 info->pending_calls++;
1463 tny_folder_store_get_folders_async (folder, folders, NULL,
1464 recurse_folders_async_cb,
1466 g_object_unref (folders);
1469 g_object_unref (G_OBJECT (folder));
1471 tny_iterator_next (iter);
1473 g_object_unref (G_OBJECT (iter));
1476 /* Remove my own pending call */
1477 info->pending_calls--;
1479 /* This means that we have all the folders */
1480 if (info->pending_calls == 0) {
1481 TnyIterator *iter_all_folders;
1482 TnyFolder *inbox = NULL;
1484 /* If there was any error do not continue */
1486 update_account_notify_user_and_free (info, NULL);
1490 iter_all_folders = tny_list_create_iterator (info->folders);
1492 /* Do a poke status over all folders */
1493 while (!tny_iterator_is_done (iter_all_folders) &&
1494 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1495 TnyFolder *folder = NULL;
1497 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1499 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1500 /* Get a reference to the INBOX */
1501 inbox = g_object_ref (folder);
1503 /* Issue a poke status over the folder */
1505 tny_folder_poke_status (folder);
1508 /* Free and go to next */
1509 g_object_unref (folder);
1510 tny_iterator_next (iter_all_folders);
1512 g_object_unref (iter_all_folders);
1514 /* Refresh the INBOX */
1516 /* Refresh the folder. Our observer receives
1517 * the new emails during folder refreshes, so
1518 * we can use observer->new_headers
1520 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1521 tny_folder_add_observer (inbox, info->inbox_observer);
1523 /* Refresh the INBOX */
1524 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1525 g_object_unref (inbox);
1527 /* We could not perform the inbox refresh but
1528 we'll try to send mails anyway */
1529 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1535 modest_mail_operation_update_account (ModestMailOperation *self,
1536 const gchar *account_name,
1538 gboolean interactive,
1539 RetrieveAllCallback retrieve_all_cb,
1540 UpdateAccountCallback callback,
1543 UpdateAccountInfo *info = NULL;
1544 ModestMailOperationPrivate *priv = NULL;
1545 ModestTnyAccountStore *account_store = NULL;
1547 ModestMailOperationState *state;
1549 /* Init mail operation */
1550 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1553 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1554 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1556 /* Get the store account */
1557 account_store = modest_runtime_get_account_store ();
1559 modest_tny_account_store_get_server_account (account_store,
1561 TNY_ACCOUNT_TYPE_STORE);
1563 /* The above function could return NULL */
1564 if (!priv->account) {
1565 /* Check if the operation was a success */
1566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1567 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1569 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1571 /* Call the user callback */
1573 callback (self, NULL, user_data);
1575 /* Notify about operation end */
1576 modest_mail_operation_notify_end (self);
1581 /* We have once seen priv->account getting finalized during this code,
1582 * therefore adding a reference (bug #82296) */
1584 g_object_ref (priv->account);
1586 /* Create the helper object */
1587 info = g_slice_new0 (UpdateAccountInfo);
1588 info->pending_calls = 1;
1589 info->folders = tny_simple_list_new ();
1590 info->mail_op = g_object_ref (self);
1591 info->poke_all = poke_all;
1592 info->interactive = interactive;
1593 info->account_name = g_strdup (account_name);
1594 info->callback = callback;
1595 info->user_data = user_data;
1596 info->retrieve_all_cb = retrieve_all_cb;
1598 /* Set account busy */
1599 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1600 modest_mail_operation_notify_start (self);
1602 /* notify about the start of the operation */
1603 state = modest_mail_operation_clone_state (self);
1607 /* Start notifying progress */
1608 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1609 g_slice_free (ModestMailOperationState, state);
1611 /* Get all folders and continue in the callback */
1612 folders = tny_simple_list_new ();
1613 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1615 recurse_folders_async_cb,
1617 g_object_unref (folders);
1619 g_object_unref (priv->account);
1624 * Used to notify the queue from the main
1625 * loop. We call it inside an idle call to achieve that
1628 idle_notify_queue (gpointer data)
1630 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1632 gdk_threads_enter ();
1633 modest_mail_operation_notify_end (mail_op);
1634 gdk_threads_leave ();
1635 g_object_unref (mail_op);
1641 compare_headers_by_date (gconstpointer a,
1644 TnyHeader **header1, **header2;
1645 time_t sent1, sent2;
1647 header1 = (TnyHeader **) a;
1648 header2 = (TnyHeader **) b;
1650 sent1 = tny_header_get_date_sent (*header1);
1651 sent2 = tny_header_get_date_sent (*header2);
1653 /* We want the most recent ones (greater time_t) at the
1662 /* ******************************************************************* */
1663 /* ************************** STORE ACTIONS ************************* */
1664 /* ******************************************************************* */
1667 ModestMailOperation *mail_op;
1668 CreateFolderUserCallback callback;
1674 create_folder_cb (TnyFolderStore *parent_folder,
1676 TnyFolder *new_folder,
1680 ModestMailOperationPrivate *priv;
1681 CreateFolderInfo *info;
1683 info = (CreateFolderInfo *) user_data;
1684 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1686 if (canceled || err) {
1687 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1689 priv->error = g_error_copy (err);
1691 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1692 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1695 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1698 /* The user will unref the new_folder */
1700 info->callback (info->mail_op, parent_folder,
1701 new_folder, info->user_data);
1703 /* Notify about operation end */
1704 modest_mail_operation_notify_end (info->mail_op);
1707 g_object_unref (info->mail_op);
1708 g_slice_free (CreateFolderInfo, info);
1712 modest_mail_operation_create_folder (ModestMailOperation *self,
1713 TnyFolderStore *parent,
1715 CreateFolderUserCallback callback,
1718 ModestMailOperationPrivate *priv;
1720 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1721 g_return_if_fail (name);
1723 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1724 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1725 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1726 g_object_ref (parent) :
1727 modest_tny_folder_get_account (TNY_FOLDER (parent));
1729 /* Check for already existing folder */
1730 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1731 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1732 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1733 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1734 _CS("ckdg_ib_folder_already_exists"));
1738 if (TNY_IS_FOLDER (parent)) {
1739 /* Check folder rules */
1740 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1741 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1742 /* Set status failed and set an error */
1743 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1744 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1745 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1746 _("mail_in_ui_folder_create_error"));
1750 if (!strcmp (name, " ") || strchr (name, '/')) {
1751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1752 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1753 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1754 _("mail_in_ui_folder_create_error"));
1758 CreateFolderInfo *info;
1760 info = g_slice_new0 (CreateFolderInfo);
1761 info->mail_op = g_object_ref (self);
1762 info->callback = callback;
1763 info->user_data = user_data;
1765 modest_mail_operation_notify_start (self);
1767 /* Create the folder */
1768 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1771 /* Call the user callback anyway */
1773 callback (self, parent, NULL, user_data);
1774 /* Notify about operation end */
1775 modest_mail_operation_notify_end (self);
1780 modest_mail_operation_remove_folder (ModestMailOperation *self,
1782 gboolean remove_to_trash)
1784 ModestMailOperationPrivate *priv;
1785 ModestTnyFolderRules rules;
1787 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1788 g_return_if_fail (TNY_IS_FOLDER (folder));
1790 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1792 /* Check folder rules */
1793 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1794 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1795 /* Set status failed and set an error */
1796 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1797 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1798 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1799 _("mail_in_ui_folder_delete_error"));
1803 /* Get the account */
1804 priv->account = modest_tny_folder_get_account (folder);
1805 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1807 /* Delete folder or move to trash */
1808 if (remove_to_trash) {
1809 TnyFolder *trash_folder = NULL;
1810 trash_folder = modest_tny_account_get_special_folder (priv->account,
1811 TNY_FOLDER_TYPE_TRASH);
1812 /* TODO: error_handling */
1814 modest_mail_operation_notify_start (self);
1815 modest_mail_operation_xfer_folder (self, folder,
1816 TNY_FOLDER_STORE (trash_folder),
1818 g_object_unref (trash_folder);
1820 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1823 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1825 modest_mail_operation_notify_start (self);
1826 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1827 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1832 g_object_unref (parent);
1834 g_warning ("%s: could not get parent folder", __FUNCTION__);
1838 /* Notify about operation end */
1839 modest_mail_operation_notify_end (self);
1843 transfer_folder_status_cb (GObject *obj,
1847 ModestMailOperation *self;
1848 ModestMailOperationPrivate *priv;
1849 ModestMailOperationState *state;
1850 XFerFolderAsyncHelper *helper;
1852 g_return_if_fail (status != NULL);
1853 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1855 helper = (XFerFolderAsyncHelper *) user_data;
1856 g_return_if_fail (helper != NULL);
1858 self = helper->mail_op;
1859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1861 priv->done = status->position;
1862 priv->total = status->of_total;
1864 state = modest_mail_operation_clone_state (self);
1866 /* This is not a GDK lock because we are a Tinymail callback
1867 * which is already GDK locked by Tinymail */
1869 /* no gdk_threads_enter (), CHECKED */
1871 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1873 /* no gdk_threads_leave (), CHECKED */
1875 g_slice_free (ModestMailOperationState, state);
1880 transfer_folder_cb (TnyFolder *folder,
1882 TnyFolderStore *into,
1883 TnyFolder *new_folder,
1887 XFerFolderAsyncHelper *helper;
1888 ModestMailOperation *self = NULL;
1889 ModestMailOperationPrivate *priv = NULL;
1891 helper = (XFerFolderAsyncHelper *) user_data;
1892 g_return_if_fail (helper != NULL);
1894 self = helper->mail_op;
1895 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1898 priv->error = g_error_copy (err);
1900 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1901 } else if (cancelled) {
1902 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1903 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1904 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1905 _("Transference of %s was cancelled."),
1906 tny_folder_get_name (folder));
1909 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1912 /* Notify about operation end */
1913 modest_mail_operation_notify_end (self);
1915 /* If user defined callback function was defined, call it */
1916 if (helper->user_callback) {
1918 /* This is not a GDK lock because we are a Tinymail callback
1919 * which is already GDK locked by Tinymail */
1921 /* no gdk_threads_enter (), CHECKED */
1922 helper->user_callback (self, new_folder, helper->user_data);
1923 /* no gdk_threads_leave () , CHECKED */
1927 g_object_unref (helper->mail_op);
1928 g_slice_free (XFerFolderAsyncHelper, helper);
1933 * This function checks if the new name is a valid name for our local
1934 * folders account. The new name could not be the same than then name
1935 * of any of the mandatory local folders
1937 * We can not rely on tinymail because tinymail does not check the
1938 * name of the virtual folders that the account could have in the case
1939 * that we're doing a rename (because it directly calls Camel which
1940 * knows nothing about our virtual folders).
1942 * In the case of an actual copy/move (i.e. move/copy a folder between
1943 * accounts) tinymail uses the tny_folder_store_create_account which
1944 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1945 * checks the new name of the folder, so this call in that case
1946 * wouldn't be needed. *But* NOTE that if tinymail changes its
1947 * implementation (if folder transfers within the same account is no
1948 * longer implemented as a rename) this call will allow Modest to work
1951 * If the new name is not valid, this function will set the status to
1952 * failed and will set also an error in the mail operation
1955 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1956 TnyFolderStore *into,
1957 const gchar *new_name)
1959 if (TNY_IS_ACCOUNT (into) &&
1960 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1961 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1963 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1964 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1965 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1966 _CS("ckdg_ib_folder_already_exists"));
1973 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1975 TnyFolderStore *parent,
1976 gboolean delete_original,
1977 XferFolderAsyncUserCallback user_callback,
1980 ModestMailOperationPrivate *priv = NULL;
1981 ModestTnyFolderRules parent_rules = 0, rules;
1982 XFerFolderAsyncHelper *helper = NULL;
1983 const gchar *folder_name = NULL;
1984 const gchar *error_msg;
1986 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1987 g_return_if_fail (TNY_IS_FOLDER (folder));
1988 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1991 folder_name = tny_folder_get_name (folder);
1993 /* Set the error msg */
1994 error_msg = _("mail_in_ui_folder_move_target_error");
1996 /* Get account and set it into mail_operation */
1997 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1998 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1999 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2001 /* Get folder rules */
2002 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2003 if (TNY_IS_FOLDER (parent))
2004 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2006 /* Apply operation constraints */
2007 if ((gpointer) parent == (gpointer) folder ||
2008 (!TNY_IS_FOLDER_STORE (parent)) ||
2009 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2012 } else if (TNY_IS_FOLDER (parent) &&
2013 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2017 } else if (TNY_IS_FOLDER (parent) &&
2018 TNY_IS_FOLDER_STORE (folder) &&
2019 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2020 TNY_FOLDER_STORE (folder))) {
2021 /* Do not move a parent into a child */
2023 } else if (TNY_IS_FOLDER_STORE (parent) &&
2024 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2025 /* Check that the new folder name is not used by any
2028 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2029 /* Check that the new folder name is not used by any
2030 special local folder */
2033 /* Create the helper */
2034 helper = g_slice_new0 (XFerFolderAsyncHelper);
2035 helper->mail_op = g_object_ref (self);
2036 helper->user_callback = user_callback;
2037 helper->user_data = user_data;
2039 /* Move/Copy folder */
2040 modest_mail_operation_notify_start (self);
2041 tny_folder_copy_async (folder,
2043 tny_folder_get_name (folder),
2046 transfer_folder_status_cb,
2052 /* Set status failed and set an error */
2053 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2054 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2055 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2058 /* Call the user callback if exists */
2060 user_callback (self, NULL, user_data);
2062 /* Notify the queue */
2063 modest_mail_operation_notify_end (self);
2067 modest_mail_operation_rename_folder (ModestMailOperation *self,
2070 XferFolderAsyncUserCallback user_callback,
2073 ModestMailOperationPrivate *priv;
2074 ModestTnyFolderRules rules;
2075 XFerFolderAsyncHelper *helper;
2077 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2078 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2079 g_return_if_fail (name);
2081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2083 /* Get account and set it into mail_operation */
2084 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2085 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2087 /* Check folder rules */
2088 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2089 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2091 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2094 TnyFolderStore *into;
2096 into = tny_folder_get_folder_store (folder);
2098 /* Check that the new folder name is not used by any
2099 special local folder */
2100 if (new_name_valid_if_local_account (priv, into, name)) {
2101 /* Create the helper */
2102 helper = g_slice_new0 (XFerFolderAsyncHelper);
2103 helper->mail_op = g_object_ref(self);
2104 helper->user_callback = user_callback;
2105 helper->user_data = user_data;
2107 /* Rename. Camel handles folder subscription/unsubscription */
2108 modest_mail_operation_notify_start (self);
2109 tny_folder_copy_async (folder, into, name, TRUE,
2111 transfer_folder_status_cb,
2116 g_object_unref (into);
2121 /* Set status failed and set an error */
2122 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2123 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2124 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2125 _("FIXME: unable to rename"));
2128 user_callback (self, NULL, user_data);
2130 /* Notify about operation end */
2131 modest_mail_operation_notify_end (self);
2134 /* ******************************************************************* */
2135 /* ************************** MSG ACTIONS ************************* */
2136 /* ******************************************************************* */
2139 modest_mail_operation_get_msg (ModestMailOperation *self,
2141 GetMsgAsyncUserCallback user_callback,
2144 GetMsgInfo *helper = NULL;
2146 ModestMailOperationPrivate *priv;
2148 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2149 g_return_if_fail (TNY_IS_HEADER (header));
2151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2152 folder = tny_header_get_folder (header);
2154 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2158 /* Get account and set it into mail_operation */
2159 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2161 /* Check for cached messages */
2162 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2163 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2165 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2167 /* Create the helper */
2168 helper = g_slice_new0 (GetMsgInfo);
2169 helper->header = g_object_ref (header);
2170 helper->mail_op = g_object_ref (self);
2171 helper->user_callback = user_callback;
2172 helper->user_data = user_data;
2173 helper->destroy_notify = NULL;
2174 helper->last_total_bytes = 0;
2175 helper->sum_total_bytes = 0;
2176 helper->total_bytes = tny_header_get_message_size (header);
2178 modest_mail_operation_notify_start (self);
2180 /* notify about the start of the operation */
2181 ModestMailOperationState *state;
2182 state = modest_mail_operation_clone_state (self);
2185 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2188 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2190 g_object_unref (G_OBJECT (folder));
2194 get_msg_status_cb (GObject *obj,
2198 GetMsgInfo *helper = NULL;
2200 g_return_if_fail (status != NULL);
2201 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2203 helper = (GetMsgInfo *) user_data;
2204 g_return_if_fail (helper != NULL);
2206 /* Notify progress */
2207 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2208 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2212 get_msg_async_cb (TnyFolder *folder,
2218 GetMsgInfo *info = NULL;
2219 ModestMailOperationPrivate *priv = NULL;
2222 info = (GetMsgInfo *) user_data;
2224 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2227 if (info->more_msgs) {
2228 tny_iterator_next (info->more_msgs);
2229 finished = (tny_iterator_is_done (info->more_msgs));
2231 finished = (priv->done == priv->total) ? TRUE : FALSE;
2234 /* If canceled by the user, ignore the error given by Tinymail */
2235 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2239 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2241 priv->error = g_error_copy ((const GError *) err);
2242 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2245 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2246 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2249 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2250 /* Set the success status before calling the user callback */
2251 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2255 /* Call the user callback */
2256 if (info->user_callback)
2257 info->user_callback (info->mail_op, info->header, canceled,
2258 msg, err, info->user_data);
2260 /* Notify about operation end if this is the last callback */
2262 /* Free user data */
2263 if (info->destroy_notify)
2264 info->destroy_notify (info->user_data);
2266 /* Notify about operation end */
2267 modest_mail_operation_notify_end (info->mail_op);
2270 if (info->more_msgs)
2271 g_object_unref (info->more_msgs);
2272 g_object_unref (info->header);
2273 g_object_unref (info->mail_op);
2274 g_slice_free (GetMsgInfo, info);
2275 } else if (info->more_msgs) {
2276 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2277 TnyFolder *folder = tny_header_get_folder (header);
2279 g_object_unref (info->header);
2280 info->header = g_object_ref (header);
2282 /* Retrieve the next message */
2283 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2285 g_object_unref (header);
2286 g_object_unref (folder);
2288 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2293 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2294 TnyList *header_list,
2295 GetMsgAsyncUserCallback user_callback,
2297 GDestroyNotify notify)
2299 ModestMailOperationPrivate *priv = NULL;
2301 TnyIterator *iter = NULL;
2302 gboolean has_uncached_messages;
2304 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2306 /* Init mail operation */
2307 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2308 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2310 priv->total = tny_list_get_length(header_list);
2312 /* Check uncached messages */
2313 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2314 !has_uncached_messages && !tny_iterator_is_done (iter);
2315 tny_iterator_next (iter)) {
2318 header = (TnyHeader *) tny_iterator_get_current (iter);
2319 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2320 has_uncached_messages = TRUE;
2321 g_object_unref (header);
2323 g_object_unref (iter);
2324 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2326 /* Get account and set it into mail_operation */
2327 if (tny_list_get_length (header_list) >= 1) {
2328 TnyIterator *iterator = tny_list_create_iterator (header_list);
2329 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2331 TnyFolder *folder = tny_header_get_folder (header);
2333 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2334 g_object_unref (folder);
2336 g_object_unref (header);
2338 g_object_unref (iterator);
2341 msg_list_size = compute_message_list_size (header_list);
2343 modest_mail_operation_notify_start (self);
2344 iter = tny_list_create_iterator (header_list);
2345 if (!tny_iterator_is_done (iter)) {
2346 /* notify about the start of the operation */
2347 ModestMailOperationState *state;
2348 state = modest_mail_operation_clone_state (self);
2351 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2354 GetMsgInfo *msg_info = NULL;
2355 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2356 TnyFolder *folder = tny_header_get_folder (header);
2358 /* Create the message info */
2359 msg_info = g_slice_new0 (GetMsgInfo);
2360 msg_info->mail_op = g_object_ref (self);
2361 msg_info->header = g_object_ref (header);
2362 msg_info->more_msgs = g_object_ref (iter);
2363 msg_info->user_callback = user_callback;
2364 msg_info->user_data = user_data;
2365 msg_info->destroy_notify = notify;
2366 msg_info->last_total_bytes = 0;
2367 msg_info->sum_total_bytes = 0;
2368 msg_info->total_bytes = msg_list_size;
2370 /* The callback will call it per each header */
2371 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2373 /* Free and go on */
2374 g_object_unref (header);
2375 g_object_unref (folder);
2376 g_slice_free (ModestMailOperationState, state);
2378 g_object_unref (iter);
2383 modest_mail_operation_remove_msg (ModestMailOperation *self,
2385 gboolean remove_to_trash /*ignored*/)
2388 ModestMailOperationPrivate *priv;
2390 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2391 g_return_if_fail (TNY_IS_HEADER (header));
2393 if (remove_to_trash)
2394 g_warning ("remove to trash is not implemented");
2396 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2397 folder = tny_header_get_folder (header);
2399 /* Get account and set it into mail_operation */
2400 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2401 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2402 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2404 /* remove message from folder */
2405 tny_folder_remove_msg (folder, header, &(priv->error));
2407 gboolean expunge, leave_on_server;
2408 const gchar *account_name;
2409 TnyAccount *account;
2410 ModestTransportStoreProtocol account_proto;
2412 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2413 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2415 modest_mail_operation_notify_start (self);
2417 /* Get leave on server setting */
2418 account = tny_folder_get_account (folder);
2419 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2421 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2424 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2426 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2427 modest_tny_folder_is_remote_folder (folder) == FALSE)
2433 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2436 g_object_unref (account);
2442 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2444 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2447 g_object_unref (G_OBJECT (folder));
2449 /* Notify about operation end */
2450 modest_mail_operation_notify_end (self);
2454 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2456 gboolean remove_to_trash /*ignored*/)
2458 TnyFolder *folder = NULL;
2459 ModestMailOperationPrivate *priv;
2460 TnyIterator *iter = NULL;
2461 TnyHeader *header = NULL;
2462 TnyList *remove_headers = NULL;
2463 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2465 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2466 g_return_if_fail (TNY_IS_LIST (headers));
2468 if (remove_to_trash)
2469 g_warning ("remove to trash is not implemented");
2471 if (tny_list_get_length(headers) == 0) {
2472 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2473 goto cleanup; /* nothing to do */
2476 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2477 remove_headers = g_object_ref(headers);
2479 /* Get folder from first header and sync it */
2480 iter = tny_list_create_iterator (headers);
2481 header = TNY_HEADER (tny_iterator_get_current (iter));
2483 folder = tny_header_get_folder (header);
2484 if (!TNY_IS_FOLDER(folder)) {
2485 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2489 /* Don't remove messages that are being sent */
2490 if (modest_tny_folder_is_local_folder (folder)) {
2491 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2493 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2494 TnyTransportAccount *traccount = NULL;
2495 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2496 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2498 ModestTnySendQueueStatus status;
2499 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2500 TnyIterator *iter = tny_list_create_iterator(headers);
2501 g_object_unref(remove_headers);
2502 remove_headers = TNY_LIST(tny_simple_list_new());
2503 while (!tny_iterator_is_done(iter)) {
2505 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2506 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2507 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2508 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2509 tny_list_append(remove_headers, G_OBJECT(hdr));
2511 g_object_unref(hdr);
2513 tny_iterator_next(iter);
2515 g_object_unref(iter);
2516 g_object_unref(traccount);
2520 /* Get account and set it into mail_operation */
2521 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2522 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2523 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2525 /* remove message from folder */
2526 modest_mail_operation_notify_start (self);
2528 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2530 gboolean expunge, leave_on_server;
2531 const gchar *account_name;
2533 TnyAccount *account;
2534 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2536 account = tny_folder_get_account (folder);
2537 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2539 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2542 proto = tny_account_get_proto (account);
2544 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2547 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2548 modest_tny_folder_is_remote_folder (folder) == FALSE)
2554 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2556 g_object_unref (account);
2562 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2564 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2569 g_object_unref (remove_headers);
2571 g_object_unref (header);
2573 g_object_unref (iter);
2575 g_object_unref (folder);
2577 /* Notify about operation end */
2578 modest_mail_operation_notify_end (self);
2582 notify_progress_of_multiple_messages (ModestMailOperation *self,
2584 gint *last_total_bytes,
2585 gint *sum_total_bytes,
2587 gboolean increment_done)
2589 ModestMailOperationPrivate *priv;
2590 ModestMailOperationState *state;
2591 gboolean is_num_bytes = FALSE;
2593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2595 /* We know that tinymail sends us information about
2596 * transferred bytes with this particular message
2598 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2599 * I just added the 'if' so we don't get runtime warning)
2601 if (status->message)
2602 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2604 state = modest_mail_operation_clone_state (self);
2605 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2606 /* We know that we're in a different message when the
2607 total number of bytes to transfer is different. Of
2608 course it could fail if we're transferring messages
2609 of the same size, but this is a workarround */
2610 if (status->of_total != *last_total_bytes) {
2611 /* We need to increment the done when there is
2612 no information about each individual
2613 message, we need to do this in message
2614 transfers, and we don't do it for getting
2618 *sum_total_bytes += *last_total_bytes;
2619 *last_total_bytes = status->of_total;
2621 state->bytes_done += status->position + *sum_total_bytes;
2622 state->bytes_total = total_bytes;
2624 /* Notify the status change. Only notify about changes
2625 referred to bytes */
2626 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2630 g_slice_free (ModestMailOperationState, state);
2634 transfer_msgs_status_cb (GObject *obj,
2638 XFerMsgsAsyncHelper *helper;
2640 g_return_if_fail (status != NULL);
2641 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2643 helper = (XFerMsgsAsyncHelper *) user_data;
2644 g_return_if_fail (helper != NULL);
2646 /* Notify progress */
2647 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2648 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2653 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2655 XFerMsgsAsyncHelper *helper;
2656 ModestMailOperation *self;
2657 ModestMailOperationPrivate *priv;
2658 gboolean finished = TRUE;
2660 helper = (XFerMsgsAsyncHelper *) user_data;
2661 self = helper->mail_op;
2663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2666 priv->error = g_error_copy (err);
2668 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2669 } else if (cancelled) {
2670 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2671 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2672 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2673 _("Error trying to refresh the contents of %s"),
2674 tny_folder_get_name (folder));
2675 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2676 if (helper->more_msgs) {
2677 /* We'll transfer the next message in the list */
2678 tny_iterator_next (helper->more_msgs);
2679 if (!tny_iterator_is_done (helper->more_msgs)) {
2680 GObject *next_header;
2681 g_object_unref (helper->headers);
2682 helper->headers = tny_simple_list_new ();
2683 next_header = tny_iterator_get_current (helper->more_msgs);
2684 tny_list_append (helper->headers, next_header);
2685 g_object_unref (next_header);
2692 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2698 /* Update folder counts */
2699 tny_folder_poke_status (folder);
2700 tny_folder_poke_status (helper->dest_folder);
2702 /* Notify about operation end */
2703 modest_mail_operation_notify_end (self);
2705 /* If user defined callback function was defined, call it */
2706 if (helper->user_callback) {
2707 /* This is not a GDK lock because we are a Tinymail callback and
2708 * Tinymail already acquires the Gdk lock */
2710 /* no gdk_threads_enter (), CHECKED */
2711 helper->user_callback (self, helper->user_data);
2712 /* no gdk_threads_leave (), CHECKED */
2716 if (helper->more_msgs)
2717 g_object_unref (helper->more_msgs);
2718 if (helper->headers)
2719 g_object_unref (helper->headers);
2720 if (helper->dest_folder)
2721 g_object_unref (helper->dest_folder);
2722 if (helper->mail_op)
2723 g_object_unref (helper->mail_op);
2724 g_slice_free (XFerMsgsAsyncHelper, helper);
2726 /* Transfer more messages */
2727 tny_folder_transfer_msgs_async (folder,
2729 helper->dest_folder,
2732 transfer_msgs_status_cb,
2738 compute_message_list_size (TnyList *headers)
2743 iter = tny_list_create_iterator (headers);
2744 while (!tny_iterator_is_done (iter)) {
2745 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2746 size += tny_header_get_message_size (header);
2747 g_object_unref (header);
2748 tny_iterator_next (iter);
2750 g_object_unref (iter);
2756 compute_message_array_size (GPtrArray *headers)
2761 for (i = 0; i < headers->len; i++) {
2762 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2763 size += tny_header_get_message_size (header);
2771 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2774 gboolean delete_original,
2775 XferMsgsAsyncUserCallback user_callback,
2778 ModestMailOperationPrivate *priv = NULL;
2779 TnyIterator *iter = NULL;
2780 TnyFolder *src_folder = NULL;
2781 XFerMsgsAsyncHelper *helper = NULL;
2782 TnyHeader *header = NULL;
2783 ModestTnyFolderRules rules = 0;
2784 TnyAccount *dst_account = NULL;
2785 gboolean leave_on_server;
2787 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2788 g_return_if_fail (headers && TNY_IS_LIST (headers));
2789 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2792 priv->total = tny_list_get_length (headers);
2794 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2795 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2797 /* Apply folder rules */
2798 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2799 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2800 /* Set status failed and set an error */
2801 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2802 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2803 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2804 _CS("ckct_ib_unable_to_paste_here"));
2805 /* Notify the queue */
2806 modest_mail_operation_notify_end (self);
2810 /* Get source folder */
2811 iter = tny_list_create_iterator (headers);
2812 header = TNY_HEADER (tny_iterator_get_current (iter));
2814 src_folder = tny_header_get_folder (header);
2815 g_object_unref (header);
2817 g_object_unref (iter);
2819 if (src_folder == NULL) {
2820 /* Notify the queue */
2821 modest_mail_operation_notify_end (self);
2823 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2828 /* Check folder source and destination */
2829 if (src_folder == folder) {
2830 /* Set status failed and set an error */
2831 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2832 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2833 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2834 _("mail_in_ui_folder_copy_target_error"));
2836 /* Notify the queue */
2837 modest_mail_operation_notify_end (self);
2840 g_object_unref (src_folder);
2844 /* Create the helper */
2845 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2846 helper->mail_op = g_object_ref(self);
2847 helper->dest_folder = g_object_ref(folder);
2848 helper->user_callback = user_callback;
2849 helper->user_data = user_data;
2850 helper->delete = delete_original;
2851 helper->last_total_bytes = 0;
2852 helper->sum_total_bytes = 0;
2853 helper->total_bytes = compute_message_list_size (headers);
2855 /* Get account and set it into mail_operation */
2856 priv->account = modest_tny_folder_get_account (src_folder);
2857 dst_account = modest_tny_folder_get_account (folder);
2859 if (priv->account == dst_account) {
2860 /* Transfer all messages at once using the fast
2861 * method. Note that depending on the server this
2862 * might not be that fast, and might not be
2863 * user-cancellable either */
2864 helper->headers = g_object_ref (headers);
2865 helper->more_msgs = NULL;
2867 /* Transfer messages one by one so the user can cancel
2870 helper->headers = tny_simple_list_new ();
2871 helper->more_msgs = tny_list_create_iterator (headers);
2872 hdr = tny_iterator_get_current (helper->more_msgs);
2873 tny_list_append (helper->headers, hdr);
2874 g_object_unref (hdr);
2877 /* If leave_on_server is set to TRUE then don't use
2878 delete_original, we always pass FALSE. This is because
2879 otherwise tinymail will try to sync the source folder and
2880 this could cause an error if we're offline while
2881 transferring an already downloaded message from a POP
2883 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2884 MODEST_PROTOCOL_STORE_POP) {
2885 const gchar *account_name;
2887 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2888 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2891 leave_on_server = FALSE;
2894 modest_mail_operation_notify_start (self);
2895 tny_folder_transfer_msgs_async (src_folder,
2898 (leave_on_server) ? FALSE : delete_original,
2900 transfer_msgs_status_cb,
2902 g_object_unref (src_folder);
2903 g_object_unref (dst_account);
2908 on_refresh_folder (TnyFolder *folder,
2913 RefreshAsyncHelper *helper = NULL;
2914 ModestMailOperation *self = NULL;
2915 ModestMailOperationPrivate *priv = NULL;
2917 helper = (RefreshAsyncHelper *) user_data;
2918 self = helper->mail_op;
2919 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2921 g_return_if_fail(priv!=NULL);
2924 priv->error = g_error_copy (error);
2925 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2930 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2931 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2932 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2933 _("Error trying to refresh the contents of %s"),
2934 tny_folder_get_name (folder));
2938 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2941 /* Call user defined callback, if it exists */
2942 if (helper->user_callback) {
2944 /* This is not a GDK lock because we are a Tinymail callback and
2945 * Tinymail already acquires the Gdk lock */
2946 helper->user_callback (self, folder, helper->user_data);
2950 g_slice_free (RefreshAsyncHelper, helper);
2952 /* Notify about operation end */
2953 modest_mail_operation_notify_end (self);
2954 g_object_unref(self);
2958 on_refresh_folder_status_update (GObject *obj,
2962 RefreshAsyncHelper *helper = NULL;
2963 ModestMailOperation *self = NULL;
2964 ModestMailOperationPrivate *priv = NULL;
2965 ModestMailOperationState *state;
2967 g_return_if_fail (user_data != NULL);
2968 g_return_if_fail (status != NULL);
2969 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2971 helper = (RefreshAsyncHelper *) user_data;
2972 self = helper->mail_op;
2973 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2975 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2977 priv->done = status->position;
2978 priv->total = status->of_total;
2980 state = modest_mail_operation_clone_state (self);
2982 /* This is not a GDK lock because we are a Tinymail callback and
2983 * Tinymail already acquires the Gdk lock */
2984 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2986 g_slice_free (ModestMailOperationState, state);
2990 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2992 RefreshAsyncUserCallback user_callback,
2995 ModestMailOperationPrivate *priv = NULL;
2996 RefreshAsyncHelper *helper = NULL;
2998 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3000 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3002 /* Get account and set it into mail_operation */
3003 priv->account = modest_tny_folder_get_account (folder);
3004 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3006 /* Create the helper */
3007 helper = g_slice_new0 (RefreshAsyncHelper);
3008 helper->mail_op = g_object_ref(self);
3009 helper->user_callback = user_callback;
3010 helper->user_data = user_data;
3012 modest_mail_operation_notify_start (self);
3014 /* notify that the operation was started */
3015 ModestMailOperationState *state;
3016 state = modest_mail_operation_clone_state (self);
3019 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3022 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3024 tny_folder_refresh_async (folder,
3026 on_refresh_folder_status_update,
3031 run_queue_stop (ModestTnySendQueue *queue,
3032 ModestMailOperation *self)
3034 ModestMailOperationPrivate *priv;
3036 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3037 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3038 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3040 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3042 modest_mail_operation_notify_end (self);
3043 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3044 g_object_unref (self);
3047 modest_mail_operation_run_queue (ModestMailOperation *self,
3048 ModestTnySendQueue *queue)
3050 ModestMailOperationPrivate *priv;
3052 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3053 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3054 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3056 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3057 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3058 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3060 modest_mail_operation_notify_start (self);
3061 g_object_ref (self);
3062 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3066 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3068 ModestMailOperationPrivate *priv;
3070 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3072 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3073 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3075 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3077 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3079 modest_mail_operation_notify_end (mail_op);
3080 g_object_unref (mail_op);
3084 modest_mail_operation_sync_folder (ModestMailOperation *self,
3085 TnyFolder *folder, gboolean expunge)
3087 ModestMailOperationPrivate *priv;
3089 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3090 g_return_if_fail (TNY_IS_FOLDER (folder));
3091 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3093 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3094 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3095 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3097 modest_mail_operation_notify_start (self);
3098 g_object_ref (self);
3099 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3103 modest_mail_operation_notify_start (ModestMailOperation *self)
3105 ModestMailOperationPrivate *priv = NULL;
3107 g_return_if_fail (self);
3109 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3111 /* Ensure that all the fields are filled correctly */
3112 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3114 /* Notify the observers about the mail operation. We do not
3115 wrapp this emission because we assume that this function is
3116 always called from within the main lock */
3117 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3122 * It's used by the mail operation queue to notify the observers
3123 * attached to that signal that the operation finished. We need to use
3124 * that because tinymail does not give us the progress of a given
3125 * operation when it finishes (it directly calls the operation
3129 modest_mail_operation_notify_end (ModestMailOperation *self)
3131 ModestMailOperationPrivate *priv = NULL;
3133 g_return_if_fail (self);
3135 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3137 /* Notify the observers about the mail operation end. We do
3138 not wrapp this emission because we assume that this
3139 function is always called from within the main lock */
3140 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3142 /* Remove the error user data */
3143 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3144 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3148 modest_mail_operation_get_account (ModestMailOperation *self)
3150 ModestMailOperationPrivate *priv = NULL;
3152 g_return_val_if_fail (self, NULL);
3154 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3156 return (priv->account) ? g_object_ref (priv->account) : NULL;
3160 modest_mail_operation_noop (ModestMailOperation *self)
3162 ModestMailOperationPrivate *priv = NULL;
3164 g_return_if_fail (self);
3166 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3167 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3168 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3172 /* This mail operation does nothing actually */
3173 modest_mail_operation_notify_start (self);
3174 modest_mail_operation_notify_end (self);
3179 modest_mail_operation_to_string (ModestMailOperation *self)
3181 const gchar *type, *status, *account_id;
3182 ModestMailOperationPrivate *priv = NULL;
3184 g_return_val_if_fail (self, NULL);
3186 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3188 /* new operations don't have anything interesting */
3189 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3190 return g_strdup_printf ("%p <new operation>", self);
3192 switch (priv->op_type) {
3193 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3194 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3195 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3196 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3197 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3198 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3199 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3200 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3201 default: type = "UNEXPECTED"; break;
3204 switch (priv->status) {
3205 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3206 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3207 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3208 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3209 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3210 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3211 default: status= "UNEXPECTED"; break;
3214 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3216 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3217 priv->done, priv->total,
3218 priv->error && priv->error->message ? priv->error->message : "");