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 /* Create the helper object */
1582 info = g_slice_new0 (UpdateAccountInfo);
1583 info->pending_calls = 1;
1584 info->folders = tny_simple_list_new ();
1585 info->mail_op = g_object_ref (self);
1586 info->poke_all = poke_all;
1587 info->interactive = interactive;
1588 info->account_name = g_strdup (account_name);
1589 info->callback = callback;
1590 info->user_data = user_data;
1591 info->retrieve_all_cb = retrieve_all_cb;
1593 /* Set account busy */
1594 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1595 modest_mail_operation_notify_start (self);
1597 /* notify about the start of the operation */
1598 state = modest_mail_operation_clone_state (self);
1602 /* Start notifying progress */
1603 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1604 g_slice_free (ModestMailOperationState, state);
1606 /* Get all folders and continue in the callback */
1607 folders = tny_simple_list_new ();
1608 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1610 recurse_folders_async_cb,
1612 g_object_unref (folders);
1616 * Used to notify the queue from the main
1617 * loop. We call it inside an idle call to achieve that
1620 idle_notify_queue (gpointer data)
1622 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1624 gdk_threads_enter ();
1625 modest_mail_operation_notify_end (mail_op);
1626 gdk_threads_leave ();
1627 g_object_unref (mail_op);
1633 compare_headers_by_date (gconstpointer a,
1636 TnyHeader **header1, **header2;
1637 time_t sent1, sent2;
1639 header1 = (TnyHeader **) a;
1640 header2 = (TnyHeader **) b;
1642 sent1 = tny_header_get_date_sent (*header1);
1643 sent2 = tny_header_get_date_sent (*header2);
1645 /* We want the most recent ones (greater time_t) at the
1654 /* ******************************************************************* */
1655 /* ************************** STORE ACTIONS ************************* */
1656 /* ******************************************************************* */
1659 ModestMailOperation *mail_op;
1660 CreateFolderUserCallback callback;
1666 create_folder_cb (TnyFolderStore *parent_folder,
1668 TnyFolder *new_folder,
1672 ModestMailOperationPrivate *priv;
1673 CreateFolderInfo *info;
1675 info = (CreateFolderInfo *) user_data;
1676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1678 if (canceled || err) {
1679 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1681 priv->error = g_error_copy (err);
1683 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1684 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1687 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1690 /* The user will unref the new_folder */
1692 info->callback (info->mail_op, parent_folder,
1693 new_folder, info->user_data);
1695 /* Notify about operation end */
1696 modest_mail_operation_notify_end (info->mail_op);
1699 g_object_unref (info->mail_op);
1700 g_slice_free (CreateFolderInfo, info);
1704 modest_mail_operation_create_folder (ModestMailOperation *self,
1705 TnyFolderStore *parent,
1707 CreateFolderUserCallback callback,
1710 ModestMailOperationPrivate *priv;
1712 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1713 g_return_if_fail (name);
1715 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1716 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1717 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1718 g_object_ref (parent) :
1719 modest_tny_folder_get_account (TNY_FOLDER (parent));
1721 /* Check for already existing folder */
1722 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1723 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1724 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1725 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1726 _CS("ckdg_ib_folder_already_exists"));
1730 if (TNY_IS_FOLDER (parent)) {
1731 /* Check folder rules */
1732 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1733 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1734 /* Set status failed and set an error */
1735 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1736 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1737 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1738 _("mail_in_ui_folder_create_error"));
1742 if (!strcmp (name, " ") || strchr (name, '/')) {
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 CreateFolderInfo *info;
1752 info = g_slice_new0 (CreateFolderInfo);
1753 info->mail_op = g_object_ref (self);
1754 info->callback = callback;
1755 info->user_data = user_data;
1757 modest_mail_operation_notify_start (self);
1759 /* Create the folder */
1760 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1763 /* Call the user callback anyway */
1765 callback (self, parent, NULL, user_data);
1766 /* Notify about operation end */
1767 modest_mail_operation_notify_end (self);
1772 modest_mail_operation_remove_folder (ModestMailOperation *self,
1774 gboolean remove_to_trash)
1776 ModestMailOperationPrivate *priv;
1777 ModestTnyFolderRules rules;
1779 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1780 g_return_if_fail (TNY_IS_FOLDER (folder));
1782 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1784 /* Check folder rules */
1785 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1786 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1787 /* Set status failed and set an error */
1788 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1789 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1790 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1791 _("mail_in_ui_folder_delete_error"));
1795 /* Get the account */
1796 priv->account = modest_tny_folder_get_account (folder);
1797 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1799 /* Delete folder or move to trash */
1800 if (remove_to_trash) {
1801 TnyFolder *trash_folder = NULL;
1802 trash_folder = modest_tny_account_get_special_folder (priv->account,
1803 TNY_FOLDER_TYPE_TRASH);
1804 /* TODO: error_handling */
1806 modest_mail_operation_notify_start (self);
1807 modest_mail_operation_xfer_folder (self, folder,
1808 TNY_FOLDER_STORE (trash_folder),
1810 g_object_unref (trash_folder);
1812 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1815 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1817 modest_mail_operation_notify_start (self);
1818 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1819 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1824 g_object_unref (parent);
1826 g_warning ("%s: could not get parent folder", __FUNCTION__);
1830 /* Notify about operation end */
1831 modest_mail_operation_notify_end (self);
1835 transfer_folder_status_cb (GObject *obj,
1839 ModestMailOperation *self;
1840 ModestMailOperationPrivate *priv;
1841 ModestMailOperationState *state;
1842 XFerFolderAsyncHelper *helper;
1844 g_return_if_fail (status != NULL);
1845 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1847 helper = (XFerFolderAsyncHelper *) user_data;
1848 g_return_if_fail (helper != NULL);
1850 self = helper->mail_op;
1851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1853 priv->done = status->position;
1854 priv->total = status->of_total;
1856 state = modest_mail_operation_clone_state (self);
1858 /* This is not a GDK lock because we are a Tinymail callback
1859 * which is already GDK locked by Tinymail */
1861 /* no gdk_threads_enter (), CHECKED */
1863 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1865 /* no gdk_threads_leave (), CHECKED */
1867 g_slice_free (ModestMailOperationState, state);
1872 transfer_folder_cb (TnyFolder *folder,
1874 TnyFolderStore *into,
1875 TnyFolder *new_folder,
1879 XFerFolderAsyncHelper *helper;
1880 ModestMailOperation *self = NULL;
1881 ModestMailOperationPrivate *priv = NULL;
1883 helper = (XFerFolderAsyncHelper *) user_data;
1884 g_return_if_fail (helper != NULL);
1886 self = helper->mail_op;
1887 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1890 priv->error = g_error_copy (err);
1892 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1893 } else if (cancelled) {
1894 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1895 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1896 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1897 _("Transference of %s was cancelled."),
1898 tny_folder_get_name (folder));
1901 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1904 /* Notify about operation end */
1905 modest_mail_operation_notify_end (self);
1907 /* If user defined callback function was defined, call it */
1908 if (helper->user_callback) {
1910 /* This is not a GDK lock because we are a Tinymail callback
1911 * which is already GDK locked by Tinymail */
1913 /* no gdk_threads_enter (), CHECKED */
1914 helper->user_callback (self, new_folder, helper->user_data);
1915 /* no gdk_threads_leave () , CHECKED */
1919 g_object_unref (helper->mail_op);
1920 g_slice_free (XFerFolderAsyncHelper, helper);
1925 * This function checks if the new name is a valid name for our local
1926 * folders account. The new name could not be the same than then name
1927 * of any of the mandatory local folders
1929 * We can not rely on tinymail because tinymail does not check the
1930 * name of the virtual folders that the account could have in the case
1931 * that we're doing a rename (because it directly calls Camel which
1932 * knows nothing about our virtual folders).
1934 * In the case of an actual copy/move (i.e. move/copy a folder between
1935 * accounts) tinymail uses the tny_folder_store_create_account which
1936 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1937 * checks the new name of the folder, so this call in that case
1938 * wouldn't be needed. *But* NOTE that if tinymail changes its
1939 * implementation (if folder transfers within the same account is no
1940 * longer implemented as a rename) this call will allow Modest to work
1943 * If the new name is not valid, this function will set the status to
1944 * failed and will set also an error in the mail operation
1947 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1948 TnyFolderStore *into,
1949 const gchar *new_name)
1951 if (TNY_IS_ACCOUNT (into) &&
1952 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1953 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1955 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1956 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1957 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1958 _CS("ckdg_ib_folder_already_exists"));
1965 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1967 TnyFolderStore *parent,
1968 gboolean delete_original,
1969 XferFolderAsyncUserCallback user_callback,
1972 ModestMailOperationPrivate *priv = NULL;
1973 ModestTnyFolderRules parent_rules = 0, rules;
1974 XFerFolderAsyncHelper *helper = NULL;
1975 const gchar *folder_name = NULL;
1976 const gchar *error_msg;
1978 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1979 g_return_if_fail (TNY_IS_FOLDER (folder));
1980 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1982 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1983 folder_name = tny_folder_get_name (folder);
1985 /* Set the error msg */
1986 error_msg = _("mail_in_ui_folder_move_target_error");
1988 /* Get account and set it into mail_operation */
1989 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1990 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1991 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1993 /* Get folder rules */
1994 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1995 if (TNY_IS_FOLDER (parent))
1996 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1998 /* Apply operation constraints */
1999 if ((gpointer) parent == (gpointer) folder ||
2000 (!TNY_IS_FOLDER_STORE (parent)) ||
2001 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2004 } else if (TNY_IS_FOLDER (parent) &&
2005 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2009 } else if (TNY_IS_FOLDER (parent) &&
2010 TNY_IS_FOLDER_STORE (folder) &&
2011 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2012 TNY_FOLDER_STORE (folder))) {
2013 /* Do not move a parent into a child */
2015 } else if (TNY_IS_FOLDER_STORE (parent) &&
2016 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2017 /* Check that the new folder name is not used by any
2020 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2021 /* Check that the new folder name is not used by any
2022 special local folder */
2025 /* Create the helper */
2026 helper = g_slice_new0 (XFerFolderAsyncHelper);
2027 helper->mail_op = g_object_ref (self);
2028 helper->user_callback = user_callback;
2029 helper->user_data = user_data;
2031 /* Move/Copy folder */
2032 modest_mail_operation_notify_start (self);
2033 tny_folder_copy_async (folder,
2035 tny_folder_get_name (folder),
2038 transfer_folder_status_cb,
2044 /* Set status failed and set an error */
2045 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2046 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2047 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2050 /* Call the user callback if exists */
2052 user_callback (self, NULL, user_data);
2054 /* Notify the queue */
2055 modest_mail_operation_notify_end (self);
2059 modest_mail_operation_rename_folder (ModestMailOperation *self,
2062 XferFolderAsyncUserCallback user_callback,
2065 ModestMailOperationPrivate *priv;
2066 ModestTnyFolderRules rules;
2067 XFerFolderAsyncHelper *helper;
2069 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2070 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2071 g_return_if_fail (name);
2073 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2075 /* Get account and set it into mail_operation */
2076 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2077 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2079 /* Check folder rules */
2080 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2081 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2083 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2086 TnyFolderStore *into;
2088 into = tny_folder_get_folder_store (folder);
2090 /* Check that the new folder name is not used by any
2091 special local folder */
2092 if (new_name_valid_if_local_account (priv, into, name)) {
2093 /* Create the helper */
2094 helper = g_slice_new0 (XFerFolderAsyncHelper);
2095 helper->mail_op = g_object_ref(self);
2096 helper->user_callback = user_callback;
2097 helper->user_data = user_data;
2099 /* Rename. Camel handles folder subscription/unsubscription */
2100 modest_mail_operation_notify_start (self);
2101 tny_folder_copy_async (folder, into, name, TRUE,
2103 transfer_folder_status_cb,
2108 g_object_unref (into);
2113 /* Set status failed and set an error */
2114 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2115 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2116 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2117 _("FIXME: unable to rename"));
2120 user_callback (self, NULL, user_data);
2122 /* Notify about operation end */
2123 modest_mail_operation_notify_end (self);
2126 /* ******************************************************************* */
2127 /* ************************** MSG ACTIONS ************************* */
2128 /* ******************************************************************* */
2131 modest_mail_operation_get_msg (ModestMailOperation *self,
2133 GetMsgAsyncUserCallback user_callback,
2136 GetMsgInfo *helper = NULL;
2138 ModestMailOperationPrivate *priv;
2140 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2141 g_return_if_fail (TNY_IS_HEADER (header));
2143 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2144 folder = tny_header_get_folder (header);
2146 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2150 /* Get account and set it into mail_operation */
2151 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2153 /* Check for cached messages */
2154 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2155 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2157 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2159 /* Create the helper */
2160 helper = g_slice_new0 (GetMsgInfo);
2161 helper->header = g_object_ref (header);
2162 helper->mail_op = g_object_ref (self);
2163 helper->user_callback = user_callback;
2164 helper->user_data = user_data;
2165 helper->destroy_notify = NULL;
2166 helper->last_total_bytes = 0;
2167 helper->sum_total_bytes = 0;
2168 helper->total_bytes = tny_header_get_message_size (header);
2170 modest_mail_operation_notify_start (self);
2172 /* notify about the start of the operation */
2173 ModestMailOperationState *state;
2174 state = modest_mail_operation_clone_state (self);
2177 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2180 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2182 g_object_unref (G_OBJECT (folder));
2186 get_msg_status_cb (GObject *obj,
2190 GetMsgInfo *helper = NULL;
2192 g_return_if_fail (status != NULL);
2193 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2195 helper = (GetMsgInfo *) user_data;
2196 g_return_if_fail (helper != NULL);
2198 /* Notify progress */
2199 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2200 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2204 get_msg_async_cb (TnyFolder *folder,
2210 GetMsgInfo *info = NULL;
2211 ModestMailOperationPrivate *priv = NULL;
2214 info = (GetMsgInfo *) user_data;
2216 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2219 if (info->more_msgs) {
2220 tny_iterator_next (info->more_msgs);
2221 finished = (tny_iterator_is_done (info->more_msgs));
2223 finished = (priv->done == priv->total) ? TRUE : FALSE;
2226 /* If canceled by the user, ignore the error given by Tinymail */
2227 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2231 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2233 priv->error = g_error_copy ((const GError *) err);
2234 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2237 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2238 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2241 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2242 /* Set the success status before calling the user callback */
2243 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2247 /* Call the user callback */
2248 if (info->user_callback)
2249 info->user_callback (info->mail_op, info->header, canceled,
2250 msg, err, info->user_data);
2252 /* Notify about operation end if this is the last callback */
2254 /* Free user data */
2255 if (info->destroy_notify)
2256 info->destroy_notify (info->user_data);
2258 /* Notify about operation end */
2259 modest_mail_operation_notify_end (info->mail_op);
2262 if (info->more_msgs)
2263 g_object_unref (info->more_msgs);
2264 g_object_unref (info->header);
2265 g_object_unref (info->mail_op);
2266 g_slice_free (GetMsgInfo, info);
2267 } else if (info->more_msgs) {
2268 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2269 TnyFolder *folder = tny_header_get_folder (header);
2271 g_object_unref (info->header);
2272 info->header = g_object_ref (header);
2274 /* Retrieve the next message */
2275 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2277 g_object_unref (header);
2278 g_object_unref (folder);
2280 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2285 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2286 TnyList *header_list,
2287 GetMsgAsyncUserCallback user_callback,
2289 GDestroyNotify notify)
2291 ModestMailOperationPrivate *priv = NULL;
2293 TnyIterator *iter = NULL;
2294 gboolean has_uncached_messages;
2296 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2298 /* Init mail operation */
2299 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2300 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2302 priv->total = tny_list_get_length(header_list);
2304 /* Check uncached messages */
2305 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2306 !has_uncached_messages && !tny_iterator_is_done (iter);
2307 tny_iterator_next (iter)) {
2310 header = (TnyHeader *) tny_iterator_get_current (iter);
2311 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2312 has_uncached_messages = TRUE;
2313 g_object_unref (header);
2315 g_object_unref (iter);
2316 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2318 /* Get account and set it into mail_operation */
2319 if (tny_list_get_length (header_list) >= 1) {
2320 TnyIterator *iterator = tny_list_create_iterator (header_list);
2321 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2323 TnyFolder *folder = tny_header_get_folder (header);
2325 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2326 g_object_unref (folder);
2328 g_object_unref (header);
2330 g_object_unref (iterator);
2333 msg_list_size = compute_message_list_size (header_list);
2335 modest_mail_operation_notify_start (self);
2336 iter = tny_list_create_iterator (header_list);
2337 if (!tny_iterator_is_done (iter)) {
2338 /* notify about the start of the operation */
2339 ModestMailOperationState *state;
2340 state = modest_mail_operation_clone_state (self);
2343 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2346 GetMsgInfo *msg_info = NULL;
2347 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2348 TnyFolder *folder = tny_header_get_folder (header);
2350 /* Create the message info */
2351 msg_info = g_slice_new0 (GetMsgInfo);
2352 msg_info->mail_op = g_object_ref (self);
2353 msg_info->header = g_object_ref (header);
2354 msg_info->more_msgs = g_object_ref (iter);
2355 msg_info->user_callback = user_callback;
2356 msg_info->user_data = user_data;
2357 msg_info->destroy_notify = notify;
2358 msg_info->last_total_bytes = 0;
2359 msg_info->sum_total_bytes = 0;
2360 msg_info->total_bytes = msg_list_size;
2362 /* The callback will call it per each header */
2363 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2365 /* Free and go on */
2366 g_object_unref (header);
2367 g_object_unref (folder);
2368 g_slice_free (ModestMailOperationState, state);
2370 g_object_unref (iter);
2375 modest_mail_operation_remove_msg (ModestMailOperation *self,
2377 gboolean remove_to_trash /*ignored*/)
2380 ModestMailOperationPrivate *priv;
2382 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2383 g_return_if_fail (TNY_IS_HEADER (header));
2385 if (remove_to_trash)
2386 g_warning ("remove to trash is not implemented");
2388 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2389 folder = tny_header_get_folder (header);
2391 /* Get account and set it into mail_operation */
2392 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2393 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2394 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2396 /* remove message from folder */
2397 tny_folder_remove_msg (folder, header, &(priv->error));
2399 gboolean expunge, leave_on_server;
2400 const gchar *account_name;
2401 TnyAccount *account;
2402 ModestTransportStoreProtocol account_proto;
2404 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2405 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2407 modest_mail_operation_notify_start (self);
2409 /* Get leave on server setting */
2410 account = tny_folder_get_account (folder);
2411 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2413 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2416 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2418 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2419 modest_tny_folder_is_remote_folder (folder) == FALSE)
2425 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2428 g_object_unref (account);
2434 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2436 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2439 g_object_unref (G_OBJECT (folder));
2441 /* Notify about operation end */
2442 modest_mail_operation_notify_end (self);
2446 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2448 gboolean remove_to_trash /*ignored*/)
2450 TnyFolder *folder = NULL;
2451 ModestMailOperationPrivate *priv;
2452 TnyIterator *iter = NULL;
2453 TnyHeader *header = NULL;
2454 TnyList *remove_headers = NULL;
2455 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2457 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2458 g_return_if_fail (TNY_IS_LIST (headers));
2460 if (remove_to_trash)
2461 g_warning ("remove to trash is not implemented");
2463 if (tny_list_get_length(headers) == 0) {
2464 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2465 goto cleanup; /* nothing to do */
2468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2469 remove_headers = g_object_ref(headers);
2471 /* Get folder from first header and sync it */
2472 iter = tny_list_create_iterator (headers);
2473 header = TNY_HEADER (tny_iterator_get_current (iter));
2475 folder = tny_header_get_folder (header);
2476 if (!TNY_IS_FOLDER(folder)) {
2477 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2481 /* Don't remove messages that are being sent */
2482 if (modest_tny_folder_is_local_folder (folder)) {
2483 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2485 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2486 TnyTransportAccount *traccount = NULL;
2487 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2488 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2490 ModestTnySendQueueStatus status;
2491 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2492 TnyIterator *iter = tny_list_create_iterator(headers);
2493 g_object_unref(remove_headers);
2494 remove_headers = TNY_LIST(tny_simple_list_new());
2495 while (!tny_iterator_is_done(iter)) {
2497 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2498 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2499 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2500 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2501 tny_list_append(remove_headers, G_OBJECT(hdr));
2503 g_object_unref(hdr);
2505 tny_iterator_next(iter);
2507 g_object_unref(iter);
2508 g_object_unref(traccount);
2512 /* Get account and set it into mail_operation */
2513 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2514 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2515 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2517 /* remove message from folder */
2518 modest_mail_operation_notify_start (self);
2520 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2522 gboolean expunge, leave_on_server;
2523 const gchar *account_name;
2525 TnyAccount *account;
2526 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2528 account = tny_folder_get_account (folder);
2529 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2531 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2534 proto = tny_account_get_proto (account);
2536 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2539 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2540 modest_tny_folder_is_remote_folder (folder) == FALSE)
2546 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2548 g_object_unref (account);
2554 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2556 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2561 g_object_unref (remove_headers);
2563 g_object_unref (header);
2565 g_object_unref (iter);
2567 g_object_unref (folder);
2569 /* Notify about operation end */
2570 modest_mail_operation_notify_end (self);
2574 notify_progress_of_multiple_messages (ModestMailOperation *self,
2576 gint *last_total_bytes,
2577 gint *sum_total_bytes,
2579 gboolean increment_done)
2581 ModestMailOperationPrivate *priv;
2582 ModestMailOperationState *state;
2583 gboolean is_num_bytes = FALSE;
2585 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2587 /* We know that tinymail sends us information about
2588 * transferred bytes with this particular message
2590 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2591 * I just added the 'if' so we don't get runtime warning)
2593 if (status->message)
2594 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2596 state = modest_mail_operation_clone_state (self);
2597 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2598 /* We know that we're in a different message when the
2599 total number of bytes to transfer is different. Of
2600 course it could fail if we're transferring messages
2601 of the same size, but this is a workarround */
2602 if (status->of_total != *last_total_bytes) {
2603 /* We need to increment the done when there is
2604 no information about each individual
2605 message, we need to do this in message
2606 transfers, and we don't do it for getting
2610 *sum_total_bytes += *last_total_bytes;
2611 *last_total_bytes = status->of_total;
2613 state->bytes_done += status->position + *sum_total_bytes;
2614 state->bytes_total = total_bytes;
2616 /* Notify the status change. Only notify about changes
2617 referred to bytes */
2618 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2622 g_slice_free (ModestMailOperationState, state);
2626 transfer_msgs_status_cb (GObject *obj,
2630 XFerMsgsAsyncHelper *helper;
2632 g_return_if_fail (status != NULL);
2633 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2635 helper = (XFerMsgsAsyncHelper *) user_data;
2636 g_return_if_fail (helper != NULL);
2638 /* Notify progress */
2639 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2640 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2645 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2647 XFerMsgsAsyncHelper *helper;
2648 ModestMailOperation *self;
2649 ModestMailOperationPrivate *priv;
2650 gboolean finished = TRUE;
2652 helper = (XFerMsgsAsyncHelper *) user_data;
2653 self = helper->mail_op;
2655 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2658 priv->error = g_error_copy (err);
2660 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2661 } else if (cancelled) {
2662 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2663 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2664 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2665 _("Error trying to refresh the contents of %s"),
2666 tny_folder_get_name (folder));
2667 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2668 if (helper->more_msgs) {
2669 /* We'll transfer the next message in the list */
2670 tny_iterator_next (helper->more_msgs);
2671 if (!tny_iterator_is_done (helper->more_msgs)) {
2672 GObject *next_header;
2673 g_object_unref (helper->headers);
2674 helper->headers = tny_simple_list_new ();
2675 next_header = tny_iterator_get_current (helper->more_msgs);
2676 tny_list_append (helper->headers, next_header);
2677 g_object_unref (next_header);
2684 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2690 /* Update folder counts */
2691 tny_folder_poke_status (folder);
2692 tny_folder_poke_status (helper->dest_folder);
2694 /* Notify about operation end */
2695 modest_mail_operation_notify_end (self);
2697 /* If user defined callback function was defined, call it */
2698 if (helper->user_callback) {
2699 /* This is not a GDK lock because we are a Tinymail callback and
2700 * Tinymail already acquires the Gdk lock */
2702 /* no gdk_threads_enter (), CHECKED */
2703 helper->user_callback (self, helper->user_data);
2704 /* no gdk_threads_leave (), CHECKED */
2708 if (helper->more_msgs)
2709 g_object_unref (helper->more_msgs);
2710 if (helper->headers)
2711 g_object_unref (helper->headers);
2712 if (helper->dest_folder)
2713 g_object_unref (helper->dest_folder);
2714 if (helper->mail_op)
2715 g_object_unref (helper->mail_op);
2716 g_slice_free (XFerMsgsAsyncHelper, helper);
2718 /* Transfer more messages */
2719 tny_folder_transfer_msgs_async (folder,
2721 helper->dest_folder,
2724 transfer_msgs_status_cb,
2730 compute_message_list_size (TnyList *headers)
2735 iter = tny_list_create_iterator (headers);
2736 while (!tny_iterator_is_done (iter)) {
2737 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2738 size += tny_header_get_message_size (header);
2739 g_object_unref (header);
2740 tny_iterator_next (iter);
2742 g_object_unref (iter);
2748 compute_message_array_size (GPtrArray *headers)
2753 for (i = 0; i < headers->len; i++) {
2754 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2755 size += tny_header_get_message_size (header);
2763 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2766 gboolean delete_original,
2767 XferMsgsAsyncUserCallback user_callback,
2770 ModestMailOperationPrivate *priv = NULL;
2771 TnyIterator *iter = NULL;
2772 TnyFolder *src_folder = NULL;
2773 XFerMsgsAsyncHelper *helper = NULL;
2774 TnyHeader *header = NULL;
2775 ModestTnyFolderRules rules = 0;
2776 TnyAccount *dst_account = NULL;
2777 gboolean leave_on_server;
2779 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2780 g_return_if_fail (headers && TNY_IS_LIST (headers));
2781 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2783 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2784 priv->total = tny_list_get_length (headers);
2786 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2787 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2789 /* Apply folder rules */
2790 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2791 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2792 /* Set status failed and set an error */
2793 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2794 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2795 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2796 _CS("ckct_ib_unable_to_paste_here"));
2797 /* Notify the queue */
2798 modest_mail_operation_notify_end (self);
2802 /* Get source folder */
2803 iter = tny_list_create_iterator (headers);
2804 header = TNY_HEADER (tny_iterator_get_current (iter));
2806 src_folder = tny_header_get_folder (header);
2807 g_object_unref (header);
2809 g_object_unref (iter);
2811 if (src_folder == NULL) {
2812 /* Notify the queue */
2813 modest_mail_operation_notify_end (self);
2815 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2820 /* Check folder source and destination */
2821 if (src_folder == folder) {
2822 /* Set status failed and set an error */
2823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2824 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2825 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2826 _("mail_in_ui_folder_copy_target_error"));
2828 /* Notify the queue */
2829 modest_mail_operation_notify_end (self);
2832 g_object_unref (src_folder);
2836 /* Create the helper */
2837 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2838 helper->mail_op = g_object_ref(self);
2839 helper->dest_folder = g_object_ref(folder);
2840 helper->user_callback = user_callback;
2841 helper->user_data = user_data;
2842 helper->delete = delete_original;
2843 helper->last_total_bytes = 0;
2844 helper->sum_total_bytes = 0;
2845 helper->total_bytes = compute_message_list_size (headers);
2847 /* Get account and set it into mail_operation */
2848 priv->account = modest_tny_folder_get_account (src_folder);
2849 dst_account = modest_tny_folder_get_account (folder);
2851 if (priv->account == dst_account) {
2852 /* Transfer all messages at once using the fast
2853 * method. Note that depending on the server this
2854 * might not be that fast, and might not be
2855 * user-cancellable either */
2856 helper->headers = g_object_ref (headers);
2857 helper->more_msgs = NULL;
2859 /* Transfer messages one by one so the user can cancel
2862 helper->headers = tny_simple_list_new ();
2863 helper->more_msgs = tny_list_create_iterator (headers);
2864 hdr = tny_iterator_get_current (helper->more_msgs);
2865 tny_list_append (helper->headers, hdr);
2866 g_object_unref (hdr);
2869 /* If leave_on_server is set to TRUE then don't use
2870 delete_original, we always pass FALSE. This is because
2871 otherwise tinymail will try to sync the source folder and
2872 this could cause an error if we're offline while
2873 transferring an already downloaded message from a POP
2875 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2876 MODEST_PROTOCOL_STORE_POP) {
2877 const gchar *account_name;
2879 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2880 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2883 leave_on_server = FALSE;
2886 modest_mail_operation_notify_start (self);
2887 tny_folder_transfer_msgs_async (src_folder,
2890 (leave_on_server) ? FALSE : delete_original,
2892 transfer_msgs_status_cb,
2894 g_object_unref (src_folder);
2895 g_object_unref (dst_account);
2900 on_refresh_folder (TnyFolder *folder,
2905 RefreshAsyncHelper *helper = NULL;
2906 ModestMailOperation *self = NULL;
2907 ModestMailOperationPrivate *priv = NULL;
2909 helper = (RefreshAsyncHelper *) user_data;
2910 self = helper->mail_op;
2911 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2913 g_return_if_fail(priv!=NULL);
2916 priv->error = g_error_copy (error);
2917 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2922 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2923 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2924 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2925 _("Error trying to refresh the contents of %s"),
2926 tny_folder_get_name (folder));
2930 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2933 /* Call user defined callback, if it exists */
2934 if (helper->user_callback) {
2936 /* This is not a GDK lock because we are a Tinymail callback and
2937 * Tinymail already acquires the Gdk lock */
2938 helper->user_callback (self, folder, helper->user_data);
2942 g_slice_free (RefreshAsyncHelper, helper);
2944 /* Notify about operation end */
2945 modest_mail_operation_notify_end (self);
2946 g_object_unref(self);
2950 on_refresh_folder_status_update (GObject *obj,
2954 RefreshAsyncHelper *helper = NULL;
2955 ModestMailOperation *self = NULL;
2956 ModestMailOperationPrivate *priv = NULL;
2957 ModestMailOperationState *state;
2959 g_return_if_fail (user_data != NULL);
2960 g_return_if_fail (status != NULL);
2961 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2963 helper = (RefreshAsyncHelper *) user_data;
2964 self = helper->mail_op;
2965 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2967 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2969 priv->done = status->position;
2970 priv->total = status->of_total;
2972 state = modest_mail_operation_clone_state (self);
2974 /* This is not a GDK lock because we are a Tinymail callback and
2975 * Tinymail already acquires the Gdk lock */
2976 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2978 g_slice_free (ModestMailOperationState, state);
2982 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2984 RefreshAsyncUserCallback user_callback,
2987 ModestMailOperationPrivate *priv = NULL;
2988 RefreshAsyncHelper *helper = NULL;
2990 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2992 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2994 /* Get account and set it into mail_operation */
2995 priv->account = modest_tny_folder_get_account (folder);
2996 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2998 /* Create the helper */
2999 helper = g_slice_new0 (RefreshAsyncHelper);
3000 helper->mail_op = g_object_ref(self);
3001 helper->user_callback = user_callback;
3002 helper->user_data = user_data;
3004 modest_mail_operation_notify_start (self);
3006 /* notify that the operation was started */
3007 ModestMailOperationState *state;
3008 state = modest_mail_operation_clone_state (self);
3011 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3014 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3016 tny_folder_refresh_async (folder,
3018 on_refresh_folder_status_update,
3023 run_queue_stop (ModestTnySendQueue *queue,
3024 ModestMailOperation *self)
3026 ModestMailOperationPrivate *priv;
3028 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3029 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3030 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3032 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3034 modest_mail_operation_notify_end (self);
3035 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3036 g_object_unref (self);
3039 modest_mail_operation_run_queue (ModestMailOperation *self,
3040 ModestTnySendQueue *queue)
3042 ModestMailOperationPrivate *priv;
3044 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3045 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3046 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3048 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3049 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3050 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3052 modest_mail_operation_notify_start (self);
3053 g_object_ref (self);
3054 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3058 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3060 ModestMailOperationPrivate *priv;
3062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3064 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3065 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3069 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3071 modest_mail_operation_notify_end (mail_op);
3072 g_object_unref (mail_op);
3076 modest_mail_operation_sync_folder (ModestMailOperation *self,
3077 TnyFolder *folder, gboolean expunge)
3079 ModestMailOperationPrivate *priv;
3081 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3082 g_return_if_fail (TNY_IS_FOLDER (folder));
3083 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3085 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3086 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3087 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3089 modest_mail_operation_notify_start (self);
3090 g_object_ref (self);
3091 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3095 modest_mail_operation_notify_start (ModestMailOperation *self)
3097 ModestMailOperationPrivate *priv = NULL;
3099 g_return_if_fail (self);
3101 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3103 /* Ensure that all the fields are filled correctly */
3104 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3106 /* Notify the observers about the mail operation. We do not
3107 wrapp this emission because we assume that this function is
3108 always called from within the main lock */
3109 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3114 * It's used by the mail operation queue to notify the observers
3115 * attached to that signal that the operation finished. We need to use
3116 * that because tinymail does not give us the progress of a given
3117 * operation when it finishes (it directly calls the operation
3121 modest_mail_operation_notify_end (ModestMailOperation *self)
3123 ModestMailOperationPrivate *priv = NULL;
3125 g_return_if_fail (self);
3127 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3129 /* Notify the observers about the mail operation end. We do
3130 not wrapp this emission because we assume that this
3131 function is always called from within the main lock */
3132 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3134 /* Remove the error user data */
3135 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3136 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3140 modest_mail_operation_get_account (ModestMailOperation *self)
3142 ModestMailOperationPrivate *priv = NULL;
3144 g_return_val_if_fail (self, NULL);
3146 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3148 return (priv->account) ? g_object_ref (priv->account) : NULL;
3152 modest_mail_operation_noop (ModestMailOperation *self)
3154 ModestMailOperationPrivate *priv = NULL;
3156 g_return_if_fail (self);
3158 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3159 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3160 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3164 /* This mail operation does nothing actually */
3165 modest_mail_operation_notify_start (self);
3166 modest_mail_operation_notify_end (self);
3171 modest_mail_operation_to_string (ModestMailOperation *self)
3173 const gchar *type, *status, *account_id;
3174 ModestMailOperationPrivate *priv = NULL;
3176 g_return_val_if_fail (self, NULL);
3178 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3180 /* new operations don't have anything interesting */
3181 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3182 return g_strdup_printf ("%p <new operation>", self);
3184 switch (priv->op_type) {
3185 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3186 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3187 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3188 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3189 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3190 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3191 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3192 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3193 default: type = "UNEXPECTED"; break;
3196 switch (priv->status) {
3197 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3198 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3199 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3200 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3201 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3202 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3203 default: status= "UNEXPECTED"; break;
3206 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3208 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3209 priv->done, priv->total,
3210 priv->error && priv->error->message ? priv->error->message : "");