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,
1449 } else if (info->poke_all) {
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);
1454 TnyList *folders = tny_simple_list_new ();
1456 /* Add to the list of all folders */
1457 tny_list_append (info->folders, (GObject *) folder);
1459 /* Add pending call */
1460 info->pending_calls++;
1462 tny_folder_store_get_folders_async (folder, folders, NULL,
1463 recurse_folders_async_cb,
1466 g_object_unref (G_OBJECT (folder));
1468 tny_iterator_next (iter);
1470 g_object_unref (G_OBJECT (iter));
1471 g_object_unref (G_OBJECT (list));
1474 /* Remove my own pending call */
1475 info->pending_calls--;
1477 /* This means that we have all the folders */
1478 if (info->pending_calls == 0) {
1479 TnyIterator *iter_all_folders;
1480 TnyFolder *inbox = NULL;
1482 /* If there was any error do not continue */
1484 update_account_notify_user_and_free (info, NULL);
1488 iter_all_folders = tny_list_create_iterator (info->folders);
1490 /* Do a poke status over all folders */
1491 while (!tny_iterator_is_done (iter_all_folders) &&
1492 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1493 TnyFolder *folder = NULL;
1495 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1497 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1498 /* Get a reference to the INBOX */
1499 inbox = g_object_ref (folder);
1501 /* Issue a poke status over the folder */
1503 tny_folder_poke_status (folder);
1506 /* Free and go to next */
1507 g_object_unref (folder);
1508 tny_iterator_next (iter_all_folders);
1510 g_object_unref (iter_all_folders);
1512 /* Refresh the INBOX */
1514 /* Refresh the folder. Our observer receives
1515 * the new emails during folder refreshes, so
1516 * we can use observer->new_headers
1518 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1519 tny_folder_add_observer (inbox, info->inbox_observer);
1521 /* Refresh the INBOX */
1522 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1523 g_object_unref (inbox);
1525 /* We could not perform the inbox refresh but
1526 we'll try to send mails anyway */
1527 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1533 modest_mail_operation_update_account (ModestMailOperation *self,
1534 const gchar *account_name,
1536 gboolean interactive,
1537 RetrieveAllCallback retrieve_all_cb,
1538 UpdateAccountCallback callback,
1541 UpdateAccountInfo *info = NULL;
1542 ModestMailOperationPrivate *priv = NULL;
1543 ModestTnyAccountStore *account_store = NULL;
1545 ModestMailOperationState *state;
1547 /* Init mail operation */
1548 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1551 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1552 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1554 /* Get the store account */
1555 account_store = modest_runtime_get_account_store ();
1557 modest_tny_account_store_get_server_account (account_store,
1559 TNY_ACCOUNT_TYPE_STORE);
1561 /* The above function could return NULL */
1562 if (!priv->account) {
1563 /* Check if the operation was a success */
1564 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1565 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1567 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1569 /* Call the user callback */
1571 callback (self, NULL, user_data);
1573 /* Notify about operation end */
1574 modest_mail_operation_notify_end (self);
1579 /* Create the helper object */
1580 info = g_slice_new0 (UpdateAccountInfo);
1581 info->pending_calls = 1;
1582 info->folders = tny_simple_list_new ();
1583 info->mail_op = g_object_ref (self);
1584 info->poke_all = poke_all;
1585 info->interactive = interactive;
1586 info->account_name = g_strdup (account_name);
1587 info->callback = callback;
1588 info->user_data = user_data;
1589 info->retrieve_all_cb = retrieve_all_cb;
1591 /* Set account busy */
1592 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1593 modest_mail_operation_notify_start (self);
1595 /* notify about the start of the operation */
1596 state = modest_mail_operation_clone_state (self);
1600 /* Start notifying progress */
1601 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1602 g_slice_free (ModestMailOperationState, state);
1604 /* Get all folders and continue in the callback */
1605 folders = tny_simple_list_new ();
1606 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1608 recurse_folders_async_cb,
1613 * Used to notify the queue from the main
1614 * loop. We call it inside an idle call to achieve that
1617 idle_notify_queue (gpointer data)
1619 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1621 gdk_threads_enter ();
1622 modest_mail_operation_notify_end (mail_op);
1623 gdk_threads_leave ();
1624 g_object_unref (mail_op);
1630 compare_headers_by_date (gconstpointer a,
1633 TnyHeader **header1, **header2;
1634 time_t sent1, sent2;
1636 header1 = (TnyHeader **) a;
1637 header2 = (TnyHeader **) b;
1639 sent1 = tny_header_get_date_sent (*header1);
1640 sent2 = tny_header_get_date_sent (*header2);
1642 /* We want the most recent ones (greater time_t) at the
1651 /* ******************************************************************* */
1652 /* ************************** STORE ACTIONS ************************* */
1653 /* ******************************************************************* */
1656 ModestMailOperation *mail_op;
1657 CreateFolderUserCallback callback;
1663 create_folder_cb (TnyFolderStore *parent_folder,
1665 TnyFolder *new_folder,
1669 ModestMailOperationPrivate *priv;
1670 CreateFolderInfo *info;
1672 info = (CreateFolderInfo *) user_data;
1673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1675 if (canceled || err) {
1676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1678 priv->error = g_error_copy (err);
1680 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1681 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1684 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1687 /* The user will unref the new_folder */
1689 info->callback (info->mail_op, parent_folder,
1690 new_folder, info->user_data);
1692 /* Notify about operation end */
1693 modest_mail_operation_notify_end (info->mail_op);
1696 g_object_unref (info->mail_op);
1697 g_slice_free (CreateFolderInfo, info);
1701 modest_mail_operation_create_folder (ModestMailOperation *self,
1702 TnyFolderStore *parent,
1704 CreateFolderUserCallback callback,
1707 ModestMailOperationPrivate *priv;
1709 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1710 g_return_if_fail (name);
1712 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1713 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1714 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1715 g_object_ref (parent) :
1716 modest_tny_folder_get_account (TNY_FOLDER (parent));
1718 /* Check for already existing folder */
1719 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1720 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1721 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1722 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1723 _CS("ckdg_ib_folder_already_exists"));
1727 if (TNY_IS_FOLDER (parent)) {
1728 /* Check folder rules */
1729 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1730 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1731 /* Set status failed and set an error */
1732 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1733 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1734 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1735 _("mail_in_ui_folder_create_error"));
1739 if (!strcmp (name, " ") || strchr (name, '/')) {
1740 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1741 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1742 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1743 _("mail_in_ui_folder_create_error"));
1747 CreateFolderInfo *info;
1749 info = g_slice_new0 (CreateFolderInfo);
1750 info->mail_op = g_object_ref (self);
1751 info->callback = callback;
1752 info->user_data = user_data;
1754 modest_mail_operation_notify_start (self);
1756 /* Create the folder */
1757 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1760 /* Call the user callback anyway */
1762 callback (self, parent, NULL, user_data);
1763 /* Notify about operation end */
1764 modest_mail_operation_notify_end (self);
1769 modest_mail_operation_remove_folder (ModestMailOperation *self,
1771 gboolean remove_to_trash)
1773 ModestMailOperationPrivate *priv;
1774 ModestTnyFolderRules rules;
1776 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1777 g_return_if_fail (TNY_IS_FOLDER (folder));
1779 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1781 /* Check folder rules */
1782 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1783 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1784 /* Set status failed and set an error */
1785 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1786 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1787 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1788 _("mail_in_ui_folder_delete_error"));
1792 /* Get the account */
1793 priv->account = modest_tny_folder_get_account (folder);
1794 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1796 /* Delete folder or move to trash */
1797 if (remove_to_trash) {
1798 TnyFolder *trash_folder = NULL;
1799 trash_folder = modest_tny_account_get_special_folder (priv->account,
1800 TNY_FOLDER_TYPE_TRASH);
1801 /* TODO: error_handling */
1803 modest_mail_operation_notify_start (self);
1804 modest_mail_operation_xfer_folder (self, folder,
1805 TNY_FOLDER_STORE (trash_folder),
1807 g_object_unref (trash_folder);
1809 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1812 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1814 modest_mail_operation_notify_start (self);
1815 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1816 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1819 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1821 g_object_unref (parent);
1823 g_warning ("%s: could not get parent folder", __FUNCTION__);
1827 /* Notify about operation end */
1828 modest_mail_operation_notify_end (self);
1832 transfer_folder_status_cb (GObject *obj,
1836 ModestMailOperation *self;
1837 ModestMailOperationPrivate *priv;
1838 ModestMailOperationState *state;
1839 XFerFolderAsyncHelper *helper;
1841 g_return_if_fail (status != NULL);
1842 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1844 helper = (XFerFolderAsyncHelper *) user_data;
1845 g_return_if_fail (helper != NULL);
1847 self = helper->mail_op;
1848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1850 priv->done = status->position;
1851 priv->total = status->of_total;
1853 state = modest_mail_operation_clone_state (self);
1855 /* This is not a GDK lock because we are a Tinymail callback
1856 * which is already GDK locked by Tinymail */
1858 /* no gdk_threads_enter (), CHECKED */
1860 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1862 /* no gdk_threads_leave (), CHECKED */
1864 g_slice_free (ModestMailOperationState, state);
1869 transfer_folder_cb (TnyFolder *folder,
1871 TnyFolderStore *into,
1872 TnyFolder *new_folder,
1876 XFerFolderAsyncHelper *helper;
1877 ModestMailOperation *self = NULL;
1878 ModestMailOperationPrivate *priv = NULL;
1880 helper = (XFerFolderAsyncHelper *) user_data;
1881 g_return_if_fail (helper != NULL);
1883 self = helper->mail_op;
1884 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1887 priv->error = g_error_copy (err);
1889 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1890 } else if (cancelled) {
1891 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1892 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1893 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1894 _("Transference of %s was cancelled."),
1895 tny_folder_get_name (folder));
1898 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1901 /* Notify about operation end */
1902 modest_mail_operation_notify_end (self);
1904 /* If user defined callback function was defined, call it */
1905 if (helper->user_callback) {
1907 /* This is not a GDK lock because we are a Tinymail callback
1908 * which is already GDK locked by Tinymail */
1910 /* no gdk_threads_enter (), CHECKED */
1911 helper->user_callback (self, new_folder, helper->user_data);
1912 /* no gdk_threads_leave () , CHECKED */
1916 g_object_unref (helper->mail_op);
1917 g_slice_free (XFerFolderAsyncHelper, helper);
1922 * This function checks if the new name is a valid name for our local
1923 * folders account. The new name could not be the same than then name
1924 * of any of the mandatory local folders
1926 * We can not rely on tinymail because tinymail does not check the
1927 * name of the virtual folders that the account could have in the case
1928 * that we're doing a rename (because it directly calls Camel which
1929 * knows nothing about our virtual folders).
1931 * In the case of an actual copy/move (i.e. move/copy a folder between
1932 * accounts) tinymail uses the tny_folder_store_create_account which
1933 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1934 * checks the new name of the folder, so this call in that case
1935 * wouldn't be needed. *But* NOTE that if tinymail changes its
1936 * implementation (if folder transfers within the same account is no
1937 * longer implemented as a rename) this call will allow Modest to work
1940 * If the new name is not valid, this function will set the status to
1941 * failed and will set also an error in the mail operation
1944 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1945 TnyFolderStore *into,
1946 const gchar *new_name)
1948 if (TNY_IS_ACCOUNT (into) &&
1949 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1950 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1953 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1954 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1955 _CS("ckdg_ib_folder_already_exists"));
1962 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1964 TnyFolderStore *parent,
1965 gboolean delete_original,
1966 XferFolderAsyncUserCallback user_callback,
1969 ModestMailOperationPrivate *priv = NULL;
1970 ModestTnyFolderRules parent_rules = 0, rules;
1971 XFerFolderAsyncHelper *helper = NULL;
1972 const gchar *folder_name = NULL;
1973 const gchar *error_msg;
1975 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1976 g_return_if_fail (TNY_IS_FOLDER (folder));
1977 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1979 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1980 folder_name = tny_folder_get_name (folder);
1982 /* Set the error msg */
1983 error_msg = _("mail_in_ui_folder_move_target_error");
1985 /* Get account and set it into mail_operation */
1986 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1987 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1990 /* Get folder rules */
1991 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1992 if (TNY_IS_FOLDER (parent))
1993 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1995 /* Apply operation constraints */
1996 if ((gpointer) parent == (gpointer) folder ||
1997 (!TNY_IS_FOLDER_STORE (parent)) ||
1998 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2001 } else if (TNY_IS_FOLDER (parent) &&
2002 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2006 } else if (TNY_IS_FOLDER (parent) &&
2007 TNY_IS_FOLDER_STORE (folder) &&
2008 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2009 TNY_FOLDER_STORE (folder))) {
2010 /* Do not move a parent into a child */
2012 } else if (TNY_IS_FOLDER_STORE (parent) &&
2013 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2014 /* Check that the new folder name is not used by any
2017 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2018 /* Check that the new folder name is not used by any
2019 special local folder */
2022 /* Create the helper */
2023 helper = g_slice_new0 (XFerFolderAsyncHelper);
2024 helper->mail_op = g_object_ref (self);
2025 helper->user_callback = user_callback;
2026 helper->user_data = user_data;
2028 /* Move/Copy folder */
2029 modest_mail_operation_notify_start (self);
2030 tny_folder_copy_async (folder,
2032 tny_folder_get_name (folder),
2035 transfer_folder_status_cb,
2041 /* Set status failed and set an error */
2042 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2043 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2044 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2047 /* Call the user callback if exists */
2049 user_callback (self, NULL, user_data);
2051 /* Notify the queue */
2052 modest_mail_operation_notify_end (self);
2056 modest_mail_operation_rename_folder (ModestMailOperation *self,
2059 XferFolderAsyncUserCallback user_callback,
2062 ModestMailOperationPrivate *priv;
2063 ModestTnyFolderRules rules;
2064 XFerFolderAsyncHelper *helper;
2066 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2067 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2068 g_return_if_fail (name);
2070 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2072 /* Get account and set it into mail_operation */
2073 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2074 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2076 /* Check folder rules */
2077 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2078 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2080 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2083 TnyFolderStore *into;
2085 into = tny_folder_get_folder_store (folder);
2087 /* Check that the new folder name is not used by any
2088 special local folder */
2089 if (new_name_valid_if_local_account (priv, into, name)) {
2090 /* Create the helper */
2091 helper = g_slice_new0 (XFerFolderAsyncHelper);
2092 helper->mail_op = g_object_ref(self);
2093 helper->user_callback = user_callback;
2094 helper->user_data = user_data;
2096 /* Rename. Camel handles folder subscription/unsubscription */
2097 modest_mail_operation_notify_start (self);
2098 tny_folder_copy_async (folder, into, name, TRUE,
2100 transfer_folder_status_cb,
2105 g_object_unref (into);
2110 /* Set status failed and set an error */
2111 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2112 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2113 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2114 _("FIXME: unable to rename"));
2117 user_callback (self, NULL, user_data);
2119 /* Notify about operation end */
2120 modest_mail_operation_notify_end (self);
2123 /* ******************************************************************* */
2124 /* ************************** MSG ACTIONS ************************* */
2125 /* ******************************************************************* */
2128 modest_mail_operation_get_msg (ModestMailOperation *self,
2130 GetMsgAsyncUserCallback user_callback,
2133 GetMsgInfo *helper = NULL;
2135 ModestMailOperationPrivate *priv;
2137 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2138 g_return_if_fail (TNY_IS_HEADER (header));
2140 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2141 folder = tny_header_get_folder (header);
2143 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2147 /* Get account and set it into mail_operation */
2148 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2150 /* Check for cached messages */
2151 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2152 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2154 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2156 /* Create the helper */
2157 helper = g_slice_new0 (GetMsgInfo);
2158 helper->header = g_object_ref (header);
2159 helper->mail_op = g_object_ref (self);
2160 helper->user_callback = user_callback;
2161 helper->user_data = user_data;
2162 helper->destroy_notify = NULL;
2163 helper->last_total_bytes = 0;
2164 helper->sum_total_bytes = 0;
2165 helper->total_bytes = tny_header_get_message_size (header);
2167 modest_mail_operation_notify_start (self);
2169 /* notify about the start of the operation */
2170 ModestMailOperationState *state;
2171 state = modest_mail_operation_clone_state (self);
2174 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2177 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2179 g_object_unref (G_OBJECT (folder));
2183 get_msg_status_cb (GObject *obj,
2187 GetMsgInfo *helper = NULL;
2189 g_return_if_fail (status != NULL);
2190 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2192 helper = (GetMsgInfo *) user_data;
2193 g_return_if_fail (helper != NULL);
2195 /* Notify progress */
2196 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2197 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2201 get_msg_async_cb (TnyFolder *folder,
2207 GetMsgInfo *info = NULL;
2208 ModestMailOperationPrivate *priv = NULL;
2211 info = (GetMsgInfo *) user_data;
2213 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2216 if (info->more_msgs) {
2217 tny_iterator_next (info->more_msgs);
2218 finished = (tny_iterator_is_done (info->more_msgs));
2220 finished = (priv->done == priv->total) ? TRUE : FALSE;
2223 /* If canceled by the user, ignore the error given by Tinymail */
2224 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2228 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2230 priv->error = g_error_copy ((const GError *) err);
2231 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2234 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2235 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2238 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2239 /* Set the success status before calling the user callback */
2240 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2244 /* Call the user callback */
2245 if (info->user_callback)
2246 info->user_callback (info->mail_op, info->header, canceled,
2247 msg, err, info->user_data);
2249 /* Notify about operation end if this is the last callback */
2251 /* Free user data */
2252 if (info->destroy_notify)
2253 info->destroy_notify (info->user_data);
2255 /* Notify about operation end */
2256 modest_mail_operation_notify_end (info->mail_op);
2259 if (info->more_msgs)
2260 g_object_unref (info->more_msgs);
2261 g_object_unref (info->header);
2262 g_object_unref (info->mail_op);
2263 g_slice_free (GetMsgInfo, info);
2264 } else if (info->more_msgs) {
2265 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2266 TnyFolder *folder = tny_header_get_folder (header);
2268 g_object_unref (info->header);
2269 info->header = g_object_ref (header);
2271 /* Retrieve the next message */
2272 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2274 g_object_unref (header);
2275 g_object_unref (folder);
2277 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2282 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2283 TnyList *header_list,
2284 GetMsgAsyncUserCallback user_callback,
2286 GDestroyNotify notify)
2288 ModestMailOperationPrivate *priv = NULL;
2290 TnyIterator *iter = NULL;
2291 gboolean has_uncached_messages;
2293 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2295 /* Init mail operation */
2296 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2297 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2299 priv->total = tny_list_get_length(header_list);
2301 /* Check uncached messages */
2302 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2303 !has_uncached_messages && !tny_iterator_is_done (iter);
2304 tny_iterator_next (iter)) {
2307 header = (TnyHeader *) tny_iterator_get_current (iter);
2308 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2309 has_uncached_messages = TRUE;
2310 g_object_unref (header);
2312 g_object_unref (iter);
2313 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2315 /* Get account and set it into mail_operation */
2316 if (tny_list_get_length (header_list) >= 1) {
2317 TnyIterator *iterator = tny_list_create_iterator (header_list);
2318 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2320 TnyFolder *folder = tny_header_get_folder (header);
2322 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2323 g_object_unref (folder);
2325 g_object_unref (header);
2327 g_object_unref (iterator);
2330 msg_list_size = compute_message_list_size (header_list);
2332 modest_mail_operation_notify_start (self);
2333 iter = tny_list_create_iterator (header_list);
2334 if (!tny_iterator_is_done (iter)) {
2335 /* notify about the start of the operation */
2336 ModestMailOperationState *state;
2337 state = modest_mail_operation_clone_state (self);
2340 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2343 GetMsgInfo *msg_info = NULL;
2344 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2345 TnyFolder *folder = tny_header_get_folder (header);
2347 /* Create the message info */
2348 msg_info = g_slice_new0 (GetMsgInfo);
2349 msg_info->mail_op = g_object_ref (self);
2350 msg_info->header = g_object_ref (header);
2351 msg_info->more_msgs = g_object_ref (iter);
2352 msg_info->user_callback = user_callback;
2353 msg_info->user_data = user_data;
2354 msg_info->destroy_notify = notify;
2355 msg_info->last_total_bytes = 0;
2356 msg_info->sum_total_bytes = 0;
2357 msg_info->total_bytes = msg_list_size;
2359 /* The callback will call it per each header */
2360 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2362 /* Free and go on */
2363 g_object_unref (header);
2364 g_object_unref (folder);
2365 g_slice_free (ModestMailOperationState, state);
2367 g_object_unref (iter);
2372 modest_mail_operation_remove_msg (ModestMailOperation *self,
2374 gboolean remove_to_trash /*ignored*/)
2377 ModestMailOperationPrivate *priv;
2379 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2380 g_return_if_fail (TNY_IS_HEADER (header));
2382 if (remove_to_trash)
2383 g_warning ("remove to trash is not implemented");
2385 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2386 folder = tny_header_get_folder (header);
2388 /* Get account and set it into mail_operation */
2389 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2390 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2391 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2393 /* remove message from folder */
2394 tny_folder_remove_msg (folder, header, &(priv->error));
2396 gboolean expunge, leave_on_server;
2397 const gchar *account_name;
2398 TnyAccount *account;
2399 ModestTransportStoreProtocol account_proto;
2401 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2402 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2404 modest_mail_operation_notify_start (self);
2406 /* Get leave on server setting */
2407 account = tny_folder_get_account (folder);
2408 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2410 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2413 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2415 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2416 modest_tny_folder_is_remote_folder (folder) == FALSE)
2422 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2425 g_object_unref (account);
2431 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2433 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2436 g_object_unref (G_OBJECT (folder));
2438 /* Notify about operation end */
2439 modest_mail_operation_notify_end (self);
2443 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2445 gboolean remove_to_trash /*ignored*/)
2447 TnyFolder *folder = NULL;
2448 ModestMailOperationPrivate *priv;
2449 TnyIterator *iter = NULL;
2450 TnyHeader *header = NULL;
2451 TnyList *remove_headers = NULL;
2452 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2454 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2455 g_return_if_fail (TNY_IS_LIST (headers));
2457 if (remove_to_trash)
2458 g_warning ("remove to trash is not implemented");
2460 if (tny_list_get_length(headers) == 0) {
2461 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2462 goto cleanup; /* nothing to do */
2465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2466 remove_headers = g_object_ref(headers);
2468 /* Get folder from first header and sync it */
2469 iter = tny_list_create_iterator (headers);
2470 header = TNY_HEADER (tny_iterator_get_current (iter));
2472 folder = tny_header_get_folder (header);
2473 if (!TNY_IS_FOLDER(folder)) {
2474 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2478 /* Don't remove messages that are being sent */
2479 if (modest_tny_folder_is_local_folder (folder)) {
2480 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2482 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2483 TnyTransportAccount *traccount = NULL;
2484 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2485 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2487 ModestTnySendQueueStatus status;
2488 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2489 TnyIterator *iter = tny_list_create_iterator(headers);
2490 g_object_unref(remove_headers);
2491 remove_headers = TNY_LIST(tny_simple_list_new());
2492 while (!tny_iterator_is_done(iter)) {
2494 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2495 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2496 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2497 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2498 tny_list_append(remove_headers, G_OBJECT(hdr));
2500 g_object_unref(hdr);
2502 tny_iterator_next(iter);
2504 g_object_unref(iter);
2505 g_object_unref(traccount);
2509 /* Get account and set it into mail_operation */
2510 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2511 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2512 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2514 /* remove message from folder */
2515 modest_mail_operation_notify_start (self);
2517 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2519 gboolean expunge, leave_on_server;
2520 const gchar *account_name;
2522 TnyAccount *account;
2523 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2525 account = tny_folder_get_account (folder);
2526 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2528 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2531 proto = tny_account_get_proto (account);
2533 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2536 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2537 modest_tny_folder_is_remote_folder (folder) == FALSE)
2543 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2545 g_object_unref (account);
2551 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2553 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2558 g_object_unref (remove_headers);
2560 g_object_unref (header);
2562 g_object_unref (iter);
2564 g_object_unref (folder);
2566 /* Notify about operation end */
2567 modest_mail_operation_notify_end (self);
2571 notify_progress_of_multiple_messages (ModestMailOperation *self,
2573 gint *last_total_bytes,
2574 gint *sum_total_bytes,
2576 gboolean increment_done)
2578 ModestMailOperationPrivate *priv;
2579 ModestMailOperationState *state;
2580 gboolean is_num_bytes = FALSE;
2582 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2584 /* We know that tinymail sends us information about
2585 * transferred bytes with this particular message
2587 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2588 * I just added the 'if' so we don't get runtime warning)
2590 if (status->message)
2591 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2593 state = modest_mail_operation_clone_state (self);
2594 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2595 /* We know that we're in a different message when the
2596 total number of bytes to transfer is different. Of
2597 course it could fail if we're transferring messages
2598 of the same size, but this is a workarround */
2599 if (status->of_total != *last_total_bytes) {
2600 /* We need to increment the done when there is
2601 no information about each individual
2602 message, we need to do this in message
2603 transfers, and we don't do it for getting
2607 *sum_total_bytes += *last_total_bytes;
2608 *last_total_bytes = status->of_total;
2610 state->bytes_done += status->position + *sum_total_bytes;
2611 state->bytes_total = total_bytes;
2613 /* Notify the status change. Only notify about changes
2614 referred to bytes */
2615 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2619 g_slice_free (ModestMailOperationState, state);
2623 transfer_msgs_status_cb (GObject *obj,
2627 XFerMsgsAsyncHelper *helper;
2629 g_return_if_fail (status != NULL);
2630 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2632 helper = (XFerMsgsAsyncHelper *) user_data;
2633 g_return_if_fail (helper != NULL);
2635 /* Notify progress */
2636 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2637 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2642 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2644 XFerMsgsAsyncHelper *helper;
2645 ModestMailOperation *self;
2646 ModestMailOperationPrivate *priv;
2647 gboolean finished = TRUE;
2649 helper = (XFerMsgsAsyncHelper *) user_data;
2650 self = helper->mail_op;
2652 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2655 priv->error = g_error_copy (err);
2657 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2658 } else if (cancelled) {
2659 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2660 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2661 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2662 _("Error trying to refresh the contents of %s"),
2663 tny_folder_get_name (folder));
2664 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2665 if (helper->more_msgs) {
2666 /* We'll transfer the next message in the list */
2667 tny_iterator_next (helper->more_msgs);
2668 if (!tny_iterator_is_done (helper->more_msgs)) {
2669 GObject *next_header;
2670 g_object_unref (helper->headers);
2671 helper->headers = tny_simple_list_new ();
2672 next_header = tny_iterator_get_current (helper->more_msgs);
2673 tny_list_append (helper->headers, next_header);
2674 g_object_unref (next_header);
2681 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2687 /* Update folder counts */
2688 tny_folder_poke_status (folder);
2689 tny_folder_poke_status (helper->dest_folder);
2691 /* Notify about operation end */
2692 modest_mail_operation_notify_end (self);
2694 /* If user defined callback function was defined, call it */
2695 if (helper->user_callback) {
2696 /* This is not a GDK lock because we are a Tinymail callback and
2697 * Tinymail already acquires the Gdk lock */
2699 /* no gdk_threads_enter (), CHECKED */
2700 helper->user_callback (self, helper->user_data);
2701 /* no gdk_threads_leave (), CHECKED */
2705 if (helper->more_msgs)
2706 g_object_unref (helper->more_msgs);
2707 if (helper->headers)
2708 g_object_unref (helper->headers);
2709 if (helper->dest_folder)
2710 g_object_unref (helper->dest_folder);
2711 if (helper->mail_op)
2712 g_object_unref (helper->mail_op);
2713 g_slice_free (XFerMsgsAsyncHelper, helper);
2715 /* Transfer more messages */
2716 tny_folder_transfer_msgs_async (folder,
2718 helper->dest_folder,
2721 transfer_msgs_status_cb,
2727 compute_message_list_size (TnyList *headers)
2732 iter = tny_list_create_iterator (headers);
2733 while (!tny_iterator_is_done (iter)) {
2734 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2735 size += tny_header_get_message_size (header);
2736 g_object_unref (header);
2737 tny_iterator_next (iter);
2739 g_object_unref (iter);
2745 compute_message_array_size (GPtrArray *headers)
2750 for (i = 0; i < headers->len; i++) {
2751 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2752 size += tny_header_get_message_size (header);
2760 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2763 gboolean delete_original,
2764 XferMsgsAsyncUserCallback user_callback,
2767 ModestMailOperationPrivate *priv = NULL;
2768 TnyIterator *iter = NULL;
2769 TnyFolder *src_folder = NULL;
2770 XFerMsgsAsyncHelper *helper = NULL;
2771 TnyHeader *header = NULL;
2772 ModestTnyFolderRules rules = 0;
2773 TnyAccount *dst_account = NULL;
2774 gboolean leave_on_server;
2776 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2777 g_return_if_fail (headers && TNY_IS_LIST (headers));
2778 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2781 priv->total = tny_list_get_length (headers);
2783 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2784 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2786 /* Apply folder rules */
2787 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2788 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2789 /* Set status failed and set an error */
2790 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2791 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2792 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2793 _CS("ckct_ib_unable_to_paste_here"));
2794 /* Notify the queue */
2795 modest_mail_operation_notify_end (self);
2799 /* Get source folder */
2800 iter = tny_list_create_iterator (headers);
2801 header = TNY_HEADER (tny_iterator_get_current (iter));
2803 src_folder = tny_header_get_folder (header);
2804 g_object_unref (header);
2806 g_object_unref (iter);
2808 if (src_folder == NULL) {
2809 /* Notify the queue */
2810 modest_mail_operation_notify_end (self);
2812 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2817 /* Check folder source and destination */
2818 if (src_folder == folder) {
2819 /* Set status failed and set an error */
2820 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2821 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2822 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2823 _("mail_in_ui_folder_copy_target_error"));
2825 /* Notify the queue */
2826 modest_mail_operation_notify_end (self);
2829 g_object_unref (src_folder);
2833 /* Create the helper */
2834 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2835 helper->mail_op = g_object_ref(self);
2836 helper->dest_folder = g_object_ref(folder);
2837 helper->user_callback = user_callback;
2838 helper->user_data = user_data;
2839 helper->delete = delete_original;
2840 helper->last_total_bytes = 0;
2841 helper->sum_total_bytes = 0;
2842 helper->total_bytes = compute_message_list_size (headers);
2844 /* Get account and set it into mail_operation */
2845 priv->account = modest_tny_folder_get_account (src_folder);
2846 dst_account = modest_tny_folder_get_account (folder);
2848 if (priv->account == dst_account) {
2849 /* Transfer all messages at once using the fast
2850 * method. Note that depending on the server this
2851 * might not be that fast, and might not be
2852 * user-cancellable either */
2853 helper->headers = g_object_ref (headers);
2854 helper->more_msgs = NULL;
2856 /* Transfer messages one by one so the user can cancel
2859 helper->headers = tny_simple_list_new ();
2860 helper->more_msgs = tny_list_create_iterator (headers);
2861 hdr = tny_iterator_get_current (helper->more_msgs);
2862 tny_list_append (helper->headers, hdr);
2863 g_object_unref (hdr);
2866 /* If leave_on_server is set to TRUE then don't use
2867 delete_original, we always pass FALSE. This is because
2868 otherwise tinymail will try to sync the source folder and
2869 this could cause an error if we're offline while
2870 transferring an already downloaded message from a POP
2872 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2873 MODEST_PROTOCOL_STORE_POP) {
2874 const gchar *account_name;
2876 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2877 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2880 leave_on_server = FALSE;
2883 modest_mail_operation_notify_start (self);
2884 tny_folder_transfer_msgs_async (src_folder,
2887 (leave_on_server) ? FALSE : delete_original,
2889 transfer_msgs_status_cb,
2891 g_object_unref (src_folder);
2892 g_object_unref (dst_account);
2897 on_refresh_folder (TnyFolder *folder,
2902 RefreshAsyncHelper *helper = NULL;
2903 ModestMailOperation *self = NULL;
2904 ModestMailOperationPrivate *priv = NULL;
2906 helper = (RefreshAsyncHelper *) user_data;
2907 self = helper->mail_op;
2908 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2910 g_return_if_fail(priv!=NULL);
2913 priv->error = g_error_copy (error);
2914 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2919 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2920 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2921 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2922 _("Error trying to refresh the contents of %s"),
2923 tny_folder_get_name (folder));
2927 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2930 /* Call user defined callback, if it exists */
2931 if (helper->user_callback) {
2933 /* This is not a GDK lock because we are a Tinymail callback and
2934 * Tinymail already acquires the Gdk lock */
2935 helper->user_callback (self, folder, helper->user_data);
2939 g_slice_free (RefreshAsyncHelper, helper);
2941 /* Notify about operation end */
2942 modest_mail_operation_notify_end (self);
2943 g_object_unref(self);
2947 on_refresh_folder_status_update (GObject *obj,
2951 RefreshAsyncHelper *helper = NULL;
2952 ModestMailOperation *self = NULL;
2953 ModestMailOperationPrivate *priv = NULL;
2954 ModestMailOperationState *state;
2956 g_return_if_fail (user_data != NULL);
2957 g_return_if_fail (status != NULL);
2958 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2960 helper = (RefreshAsyncHelper *) user_data;
2961 self = helper->mail_op;
2962 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2964 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2966 priv->done = status->position;
2967 priv->total = status->of_total;
2969 state = modest_mail_operation_clone_state (self);
2971 /* This is not a GDK lock because we are a Tinymail callback and
2972 * Tinymail already acquires the Gdk lock */
2973 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2975 g_slice_free (ModestMailOperationState, state);
2979 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2981 RefreshAsyncUserCallback user_callback,
2984 ModestMailOperationPrivate *priv = NULL;
2985 RefreshAsyncHelper *helper = NULL;
2987 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2989 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2991 /* Get account and set it into mail_operation */
2992 priv->account = modest_tny_folder_get_account (folder);
2993 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2995 /* Create the helper */
2996 helper = g_slice_new0 (RefreshAsyncHelper);
2997 helper->mail_op = g_object_ref(self);
2998 helper->user_callback = user_callback;
2999 helper->user_data = user_data;
3001 modest_mail_operation_notify_start (self);
3003 /* notify that the operation was started */
3004 ModestMailOperationState *state;
3005 state = modest_mail_operation_clone_state (self);
3008 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3011 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3013 tny_folder_refresh_async (folder,
3015 on_refresh_folder_status_update,
3020 run_queue_stop (ModestTnySendQueue *queue,
3021 ModestMailOperation *self)
3023 ModestMailOperationPrivate *priv;
3025 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3026 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3027 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3029 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3031 modest_mail_operation_notify_end (self);
3032 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3033 g_object_unref (self);
3036 modest_mail_operation_run_queue (ModestMailOperation *self,
3037 ModestTnySendQueue *queue)
3039 ModestMailOperationPrivate *priv;
3041 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3042 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3043 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3045 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3046 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3047 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3049 modest_mail_operation_notify_start (self);
3050 g_object_ref (self);
3051 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3055 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3057 ModestMailOperationPrivate *priv;
3059 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3061 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3062 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3064 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3066 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3068 modest_mail_operation_notify_end (mail_op);
3069 g_object_unref (mail_op);
3073 modest_mail_operation_sync_folder (ModestMailOperation *self,
3074 TnyFolder *folder, gboolean expunge)
3076 ModestMailOperationPrivate *priv;
3078 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3079 g_return_if_fail (TNY_IS_FOLDER (folder));
3080 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3082 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3083 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3084 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3086 modest_mail_operation_notify_start (self);
3087 g_object_ref (self);
3088 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3092 modest_mail_operation_notify_start (ModestMailOperation *self)
3094 ModestMailOperationPrivate *priv = NULL;
3096 g_return_if_fail (self);
3098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3100 /* Ensure that all the fields are filled correctly */
3101 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3103 /* Notify the observers about the mail operation. We do not
3104 wrapp this emission because we assume that this function is
3105 always called from within the main lock */
3106 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3111 * It's used by the mail operation queue to notify the observers
3112 * attached to that signal that the operation finished. We need to use
3113 * that because tinymail does not give us the progress of a given
3114 * operation when it finishes (it directly calls the operation
3118 modest_mail_operation_notify_end (ModestMailOperation *self)
3120 ModestMailOperationPrivate *priv = NULL;
3122 g_return_if_fail (self);
3124 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3126 /* Notify the observers about the mail operation end. We do
3127 not wrapp this emission because we assume that this
3128 function is always called from within the main lock */
3129 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3131 /* Remove the error user data */
3132 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3133 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3137 modest_mail_operation_get_account (ModestMailOperation *self)
3139 ModestMailOperationPrivate *priv = NULL;
3141 g_return_val_if_fail (self, NULL);
3143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3145 return (priv->account) ? g_object_ref (priv->account) : NULL;
3149 modest_mail_operation_noop (ModestMailOperation *self)
3151 ModestMailOperationPrivate *priv = NULL;
3153 g_return_if_fail (self);
3155 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3156 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3157 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3161 /* This mail operation does nothing actually */
3162 modest_mail_operation_notify_start (self);
3163 modest_mail_operation_notify_end (self);
3168 modest_mail_operation_to_string (ModestMailOperation *self)
3170 const gchar *type, *status, *account_id;
3171 ModestMailOperationPrivate *priv = NULL;
3173 g_return_val_if_fail (self, NULL);
3175 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3177 /* new operations don't have anything interesting */
3178 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3179 return g_strdup_printf ("%p <new operation>", self);
3181 switch (priv->op_type) {
3182 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3183 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3184 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3185 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3186 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3187 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3188 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3189 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3190 default: type = "UNEXPECTED"; break;
3193 switch (priv->status) {
3194 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3195 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3196 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3197 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3198 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3199 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3200 default: status= "UNEXPECTED"; break;
3203 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3205 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3206 priv->done, priv->total,
3207 priv->error && priv->error->message ? priv->error->message : "");