1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers);
100 static guint compute_message_array_size (GPtrArray *headers);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 enum _ModestMailOperationSignals
112 PROGRESS_CHANGED_SIGNAL,
113 OPERATION_STARTED_SIGNAL,
114 OPERATION_FINISHED_SIGNAL,
118 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
119 struct _ModestMailOperationPrivate {
125 ErrorCheckingUserCallback error_checking;
126 gpointer error_checking_user_data;
127 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
128 ModestMailOperationStatus status;
129 ModestMailOperationTypeOperation op_type;
132 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
133 MODEST_TYPE_MAIL_OPERATION, \
134 ModestMailOperationPrivate))
136 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
137 priv->status = new_status;\
142 GetMsgAsyncUserCallback user_callback;
144 TnyIterator *more_msgs;
146 ModestMailOperation *mail_op;
147 GDestroyNotify destroy_notify;
148 gint last_total_bytes;
149 gint sum_total_bytes;
153 typedef struct _RefreshAsyncHelper {
154 ModestMailOperation *mail_op;
155 RefreshAsyncUserCallback user_callback;
157 } RefreshAsyncHelper;
159 typedef struct _XFerMsgsAsyncHelper
161 ModestMailOperation *mail_op;
163 TnyIterator *more_msgs;
164 TnyFolder *dest_folder;
165 XferMsgsAsyncUserCallback user_callback;
168 gint last_total_bytes;
169 gint sum_total_bytes;
171 } XFerMsgsAsyncHelper;
173 typedef struct _XFerFolderAsyncHelper
175 ModestMailOperation *mail_op;
176 XferFolderAsyncUserCallback user_callback;
178 } XFerFolderAsyncHelper;
180 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
184 static void modest_mail_operation_create_msg (ModestMailOperation *self,
185 const gchar *from, const gchar *to,
186 const gchar *cc, const gchar *bcc,
187 const gchar *subject, const gchar *plain_body,
188 const gchar *html_body, const GList *attachments_list,
189 const GList *images_list,
190 TnyHeaderFlags priority_flags,
191 ModestMailOperationCreateMsgCallback callback,
194 static gboolean idle_notify_queue (gpointer data);
197 ModestMailOperation *mail_op;
205 GList *attachments_list;
207 TnyHeaderFlags priority_flags;
208 ModestMailOperationCreateMsgCallback callback;
214 ModestMailOperation *mail_op;
216 ModestMailOperationCreateMsgCallback callback;
221 static GObjectClass *parent_class = NULL;
223 static guint signals[NUM_SIGNALS] = {0};
226 modest_mail_operation_get_type (void)
228 static GType my_type = 0;
230 static const GTypeInfo my_info = {
231 sizeof(ModestMailOperationClass),
232 NULL, /* base init */
233 NULL, /* base finalize */
234 (GClassInitFunc) modest_mail_operation_class_init,
235 NULL, /* class finalize */
236 NULL, /* class data */
237 sizeof(ModestMailOperation),
239 (GInstanceInitFunc) modest_mail_operation_init,
242 my_type = g_type_register_static (G_TYPE_OBJECT,
243 "ModestMailOperation",
250 modest_mail_operation_class_init (ModestMailOperationClass *klass)
252 GObjectClass *gobject_class;
253 gobject_class = (GObjectClass*) klass;
255 parent_class = g_type_class_peek_parent (klass);
256 gobject_class->finalize = modest_mail_operation_finalize;
258 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
261 * ModestMailOperation::progress-changed
262 * @self: the #MailOperation that emits the signal
263 * @user_data: user data set when the signal handler was connected
265 * Emitted when the progress of a mail operation changes
267 signals[PROGRESS_CHANGED_SIGNAL] =
268 g_signal_new ("progress-changed",
269 G_TYPE_FROM_CLASS (gobject_class),
271 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
273 g_cclosure_marshal_VOID__POINTER,
274 G_TYPE_NONE, 1, G_TYPE_POINTER);
278 * This signal is issued whenever a mail operation starts, and
279 * starts mean when the tinymail operation is issued. This
280 * means that it could happen that something wrong happens and
281 * the tinymail function is never called. In this situation a
282 * operation-finished will be issued without any
285 signals[OPERATION_STARTED_SIGNAL] =
286 g_signal_new ("operation-started",
287 G_TYPE_FROM_CLASS (gobject_class),
289 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
291 g_cclosure_marshal_VOID__VOID,
296 * This signal is issued whenever a mail operation
297 * finishes. Note that this signal could be issued without any
298 * previous "operation-started" signal, because this last one
299 * is only issued when the tinymail operation is successfully
302 signals[OPERATION_FINISHED_SIGNAL] =
303 g_signal_new ("operation-finished",
304 G_TYPE_FROM_CLASS (gobject_class),
306 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
308 g_cclosure_marshal_VOID__VOID,
313 modest_mail_operation_init (ModestMailOperation *obj)
315 ModestMailOperationPrivate *priv;
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
319 priv->account = NULL;
320 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
321 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
326 priv->error_checking = NULL;
327 priv->error_checking_user_data = NULL;
331 modest_mail_operation_finalize (GObject *obj)
333 ModestMailOperationPrivate *priv;
335 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
340 g_error_free (priv->error);
344 g_object_unref (priv->source);
348 g_object_unref (priv->account);
349 priv->account = NULL;
353 G_OBJECT_CLASS(parent_class)->finalize (obj);
357 modest_mail_operation_new (GObject *source)
359 ModestMailOperation *obj;
360 ModestMailOperationPrivate *priv;
362 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
366 priv->source = g_object_ref(source);
372 modest_mail_operation_new_with_error_handling (GObject *source,
373 ErrorCheckingUserCallback error_handler,
375 ErrorCheckingUserDataDestroyer error_handler_destroyer)
377 ModestMailOperation *obj;
378 ModestMailOperationPrivate *priv;
380 obj = modest_mail_operation_new (source);
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
383 g_return_val_if_fail (error_handler != NULL, obj);
384 priv->error_checking = error_handler;
385 priv->error_checking_user_data = user_data;
386 priv->error_checking_user_data_destroyer = error_handler_destroyer;
392 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
394 ModestMailOperationPrivate *priv;
396 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
399 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
401 /* Call the user callback */
402 if (priv->error_checking != NULL)
403 priv->error_checking (self, priv->error_checking_user_data);
407 ModestMailOperationTypeOperation
408 modest_mail_operation_get_type_operation (ModestMailOperation *self)
410 ModestMailOperationPrivate *priv;
412 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
413 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
415 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
417 return priv->op_type;
421 modest_mail_operation_is_mine (ModestMailOperation *self,
424 ModestMailOperationPrivate *priv;
426 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
430 if (priv->source == NULL) return FALSE;
432 return priv->source == me;
436 modest_mail_operation_get_source (ModestMailOperation *self)
438 ModestMailOperationPrivate *priv;
440 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
445 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
449 return (priv->source) ? g_object_ref (priv->source) : NULL;
452 ModestMailOperationStatus
453 modest_mail_operation_get_status (ModestMailOperation *self)
455 ModestMailOperationPrivate *priv;
457 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
458 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
459 MODEST_MAIL_OPERATION_STATUS_INVALID);
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
463 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
464 return MODEST_MAIL_OPERATION_STATUS_INVALID;
471 modest_mail_operation_get_error (ModestMailOperation *self)
473 ModestMailOperationPrivate *priv;
475 g_return_val_if_fail (self, NULL);
476 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
481 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
489 modest_mail_operation_cancel (ModestMailOperation *self)
491 ModestMailOperationPrivate *priv;
492 gboolean canceled = FALSE;
494 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
499 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
501 /* Cancel the mail operation */
502 g_return_val_if_fail (priv->account, FALSE);
503 tny_account_cancel (priv->account);
505 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
506 ModestTnySendQueue *queue;
507 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
509 /* Cancel the sending of the following next messages */
510 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
517 modest_mail_operation_get_task_done (ModestMailOperation *self)
519 ModestMailOperationPrivate *priv;
521 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
529 modest_mail_operation_get_task_total (ModestMailOperation *self)
531 ModestMailOperationPrivate *priv;
533 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
541 modest_mail_operation_is_finished (ModestMailOperation *self)
543 ModestMailOperationPrivate *priv;
544 gboolean retval = FALSE;
546 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
549 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
551 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
552 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
553 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
554 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
564 * Creates an image of the current state of a mail operation, the
565 * caller must free it
567 static ModestMailOperationState *
568 modest_mail_operation_clone_state (ModestMailOperation *self)
570 ModestMailOperationState *state;
571 ModestMailOperationPrivate *priv;
573 /* FIXME: this should be fixed properly
575 * in some cases, priv was NULL, so checking here to
578 g_return_val_if_fail (self, NULL);
579 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
580 g_return_val_if_fail (priv, NULL);
585 state = g_slice_new (ModestMailOperationState);
587 state->status = priv->status;
588 state->op_type = priv->op_type;
589 state->done = priv->done;
590 state->total = priv->total;
591 state->finished = modest_mail_operation_is_finished (self);
592 state->bytes_done = 0;
593 state->bytes_total = 0;
598 /* ******************************************************************* */
599 /* ************************** SEND ACTIONS ************************* */
600 /* ******************************************************************* */
603 modest_mail_operation_send_mail (ModestMailOperation *self,
604 TnyTransportAccount *transport_account,
607 TnySendQueue *send_queue = NULL;
608 ModestMailOperationPrivate *priv;
610 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
611 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
612 g_return_if_fail (msg && TNY_IS_MSG (msg));
614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
616 /* Get account and set it into mail_operation */
617 priv->account = g_object_ref (transport_account);
618 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
622 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
623 if (!TNY_IS_SEND_QUEUE(send_queue)) {
625 g_error_free (priv->error);
628 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
629 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
630 "modest: could not find send queue for account\n");
631 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
632 modest_mail_operation_notify_end (self);
635 /* Add the msg to the queue */
636 modest_mail_operation_notify_start (self);
638 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
639 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE);
642 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
644 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
646 modest_mail_operation_notify_end (self);
653 idle_create_msg_cb (gpointer idle_data)
655 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
657 /* This is a GDK lock because we are an idle callback and
658 * info->callback can contain Gtk+ code */
660 gdk_threads_enter (); /* CHECKED */
661 info->callback (info->mail_op, info->msg, info->userdata);
663 g_object_unref (info->mail_op);
665 g_object_unref (info->msg);
666 g_slice_free (CreateMsgIdleInfo, info);
667 gdk_threads_leave (); /* CHECKED */
673 create_msg_thread (gpointer thread_data)
675 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
676 TnyMsg *new_msg = NULL;
677 ModestMailOperationPrivate *priv;
679 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
680 if (info->html_body == NULL) {
681 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
682 info->bcc, info->subject, info->plain_body,
683 info->attachments_list,
686 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
687 info->bcc, info->subject, info->html_body,
688 info->plain_body, info->attachments_list,
696 /* Set priority flags in message */
697 header = tny_msg_get_header (new_msg);
698 tny_header_set_flag (header, info->priority_flags);
700 /* Set attachment flags in message */
701 if (info->attachments_list != NULL)
702 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
704 g_object_unref (G_OBJECT(header));
706 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
708 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
709 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
710 "modest: failed to create a new msg\n");
718 g_free (info->plain_body);
719 g_free (info->html_body);
720 g_free (info->subject);
721 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
722 g_list_free (info->attachments_list);
723 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
724 g_list_free (info->images_list);
726 if (info->callback) {
727 CreateMsgIdleInfo *idle_info;
728 idle_info = g_slice_new0 (CreateMsgIdleInfo);
729 idle_info->mail_op = g_object_ref (info->mail_op);
730 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
731 idle_info->callback = info->callback;
732 idle_info->userdata = info->userdata;
733 g_idle_add (idle_create_msg_cb, idle_info);
735 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
738 g_object_unref (info->mail_op);
739 g_slice_free (CreateMsgInfo, info);
740 if (new_msg) g_object_unref(new_msg);
746 modest_mail_operation_create_msg (ModestMailOperation *self,
747 const gchar *from, const gchar *to,
748 const gchar *cc, const gchar *bcc,
749 const gchar *subject, const gchar *plain_body,
750 const gchar *html_body,
751 const GList *attachments_list,
752 const GList *images_list,
753 TnyHeaderFlags priority_flags,
754 ModestMailOperationCreateMsgCallback callback,
757 CreateMsgInfo *info = NULL;
759 info = g_slice_new0 (CreateMsgInfo);
760 info->mail_op = g_object_ref (self);
762 info->from = g_strdup (from);
763 info->to = g_strdup (to);
764 info->cc = g_strdup (cc);
765 info->bcc = g_strdup (bcc);
766 info->subject = g_strdup (subject);
767 info->plain_body = g_strdup (plain_body);
768 info->html_body = g_strdup (html_body);
769 info->attachments_list = g_list_copy ((GList *) attachments_list);
770 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
771 info->images_list = g_list_copy ((GList *) images_list);
772 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
773 info->priority_flags = priority_flags;
775 info->callback = callback;
776 info->userdata = userdata;
778 g_thread_create (create_msg_thread, info, FALSE, NULL);
783 TnyTransportAccount *transport_account;
788 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
792 ModestMailOperationPrivate *priv = NULL;
793 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
794 TnyFolder *draft_folder = NULL;
795 TnyFolder *outbox_folder = NULL;
796 TnyHeader *header = NULL;
798 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
801 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
802 modest_mail_operation_notify_end (self);
806 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
807 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
808 modest_mail_operation_notify_end (self);
812 /* Call mail operation */
813 modest_mail_operation_send_mail (self, info->transport_account, msg);
815 if (info->draft_msg != NULL) {
816 TnyList *tmp_headers = NULL;
817 TnyFolder *folder = NULL;
818 TnyFolder *src_folder = NULL;
819 TnyFolderType folder_type;
820 TnyTransportAccount *transport_account = NULL;
822 /* To remove the old mail from its source folder, we need to get the
823 * transport account of the original draft message (the transport account
824 * might have been changed by the user) */
825 header = tny_msg_get_header (info->draft_msg);
826 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
827 modest_runtime_get_account_store(), header);
828 if (transport_account == NULL)
829 transport_account = g_object_ref(info->transport_account);
830 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
831 TNY_FOLDER_TYPE_DRAFTS);
832 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
833 TNY_FOLDER_TYPE_OUTBOX);
834 g_object_unref(transport_account);
837 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
841 if (!outbox_folder) {
842 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
847 folder = tny_msg_get_folder (info->draft_msg);
848 if (folder == NULL) goto end;
849 folder_type = modest_tny_folder_guess_folder_type (folder);
851 if (folder_type == TNY_FOLDER_TYPE_INVALID)
852 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
854 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
855 src_folder = outbox_folder;
857 src_folder = draft_folder;
859 /* Note: This can fail (with a warning) if the message is not really already in a folder,
860 * because this function requires it to have a UID. */
861 tmp_headers = tny_simple_list_new ();
862 tny_list_append (tmp_headers, (GObject*) header);
863 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
864 g_object_unref (tmp_headers);
865 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
867 g_object_unref (folder);
872 g_object_unref (header);
874 g_object_unref (info->draft_msg);
876 g_object_unref (draft_folder);
878 g_object_unref (outbox_folder);
879 if (info->transport_account)
880 g_object_unref (info->transport_account);
881 g_slice_free (SendNewMailInfo, info);
885 modest_mail_operation_send_new_mail (ModestMailOperation *self,
886 TnyTransportAccount *transport_account,
888 const gchar *from, const gchar *to,
889 const gchar *cc, const gchar *bcc,
890 const gchar *subject, const gchar *plain_body,
891 const gchar *html_body,
892 const GList *attachments_list,
893 const GList *images_list,
894 TnyHeaderFlags priority_flags)
896 ModestMailOperationPrivate *priv = NULL;
897 SendNewMailInfo *info;
899 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
900 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
902 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
903 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
904 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
905 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
907 /* Check parametters */
909 /* Set status failed and set an error */
910 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
911 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
912 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
913 _("Error trying to send a mail. You need to set at least one recipient"));
916 info = g_slice_new0 (SendNewMailInfo);
917 info->transport_account = transport_account;
918 if (transport_account)
919 g_object_ref (transport_account);
920 info->draft_msg = draft_msg;
922 g_object_ref (draft_msg);
925 modest_mail_operation_notify_start (self);
926 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
927 attachments_list, images_list, priority_flags,
928 modest_mail_operation_send_new_mail_cb, info);
934 TnyTransportAccount *transport_account;
936 SaveToDraftstCallback callback;
940 ModestMailOperation *mailop;
941 } SaveToDraftsAddMsgInfo;
944 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
949 ModestMailOperationPrivate *priv = NULL;
950 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
951 GError *io_error = NULL;
953 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
955 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
956 io_error = priv->error;
960 g_warning ("%s: priv->error != NULL", __FUNCTION__);
961 g_error_free(priv->error);
964 priv->error = (err == NULL) ? NULL : g_error_copy(err);
966 if ((!priv->error) && (info->draft_msg != NULL)) {
967 TnyHeader *header = tny_msg_get_header (info->draft_msg);
968 TnyFolder *src_folder = tny_header_get_folder (header);
970 /* Remove the old draft */
971 tny_folder_remove_msg (src_folder, header, NULL);
973 /* Synchronize to expunge and to update the msg counts */
974 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
975 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
977 g_object_unref (G_OBJECT(header));
978 g_object_unref (G_OBJECT(src_folder));
982 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
984 g_error_free (io_error);
987 } else if (io_error) {
988 priv->error = io_error;
989 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
991 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
994 /* Call the user callback */
996 info->callback (info->mailop, info->msg, info->user_data);
998 if (info->transport_account)
999 g_object_unref (G_OBJECT(info->transport_account));
1000 if (info->draft_msg)
1001 g_object_unref (G_OBJECT (info->draft_msg));
1003 g_object_unref (G_OBJECT(info->drafts));
1005 g_object_unref (G_OBJECT (info->msg));
1007 modest_mail_operation_notify_end (info->mailop);
1008 g_object_unref(info->mailop);
1009 g_slice_free (SaveToDraftsAddMsgInfo, info);
1014 TnyTransportAccount *transport_account;
1016 SaveToDraftstCallback callback;
1021 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1025 TnyFolder *drafts = NULL;
1026 ModestMailOperationPrivate *priv = NULL;
1027 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1029 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1032 if (!(priv->error)) {
1033 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1034 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1035 "modest: failed to create a new msg\n");
1038 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1039 TNY_FOLDER_TYPE_DRAFTS);
1040 if (!drafts && !(priv->error)) {
1041 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1042 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1043 "modest: failed to create a new msg\n");
1047 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1048 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1049 cb_info->transport_account = g_object_ref(info->transport_account);
1050 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1051 cb_info->callback = info->callback;
1052 cb_info->user_data = info->user_data;
1053 cb_info->drafts = g_object_ref(drafts);
1054 cb_info->msg = g_object_ref(msg);
1055 cb_info->mailop = g_object_ref(self);
1056 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1059 /* Call the user callback */
1060 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1062 info->callback (self, msg, info->user_data);
1063 modest_mail_operation_notify_end (self);
1067 g_object_unref (G_OBJECT(drafts));
1068 if (info->draft_msg)
1069 g_object_unref (G_OBJECT (info->draft_msg));
1070 if (info->transport_account)
1071 g_object_unref (G_OBJECT(info->transport_account));
1072 g_slice_free (SaveToDraftsInfo, info);
1076 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1077 TnyTransportAccount *transport_account,
1079 const gchar *from, const gchar *to,
1080 const gchar *cc, const gchar *bcc,
1081 const gchar *subject, const gchar *plain_body,
1082 const gchar *html_body,
1083 const GList *attachments_list,
1084 const GList *images_list,
1085 TnyHeaderFlags priority_flags,
1086 SaveToDraftstCallback callback,
1089 ModestMailOperationPrivate *priv = NULL;
1090 SaveToDraftsInfo *info = NULL;
1092 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1093 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1095 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1097 /* Get account and set it into mail_operation */
1098 priv->account = g_object_ref (transport_account);
1099 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1101 info = g_slice_new0 (SaveToDraftsInfo);
1102 info->transport_account = g_object_ref (transport_account);
1103 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1104 info->callback = callback;
1105 info->user_data = user_data;
1107 modest_mail_operation_notify_start (self);
1108 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1109 attachments_list, images_list, priority_flags,
1110 modest_mail_operation_save_to_drafts_cb, info);
1115 ModestMailOperation *mail_op;
1116 TnyMimePart *mime_part;
1118 GetMimePartSizeCallback callback;
1120 } GetMimePartSizeInfo;
1122 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1123 /* We use this folder observer to track the headers that have been
1124 * added to a folder */
1127 TnyList *new_headers;
1128 } InternalFolderObserver;
1131 GObjectClass parent;
1132 } InternalFolderObserverClass;
1134 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1136 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1137 internal_folder_observer,
1139 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1143 foreach_add_item (gpointer header, gpointer user_data)
1145 tny_list_prepend (TNY_LIST (user_data),
1146 g_object_ref (G_OBJECT (header)));
1149 /* This is the method that looks for new messages in a folder */
1151 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1153 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1155 TnyFolderChangeChanged changed;
1157 changed = tny_folder_change_get_changed (change);
1159 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1162 /* Get added headers */
1163 list = tny_simple_list_new ();
1164 tny_folder_change_get_added_headers (change, list);
1166 /* Add them to the folder observer */
1167 tny_list_foreach (list, foreach_add_item,
1168 derived->new_headers);
1170 g_object_unref (G_OBJECT (list));
1175 internal_folder_observer_init (InternalFolderObserver *self)
1177 self->new_headers = tny_simple_list_new ();
1180 internal_folder_observer_finalize (GObject *object)
1182 InternalFolderObserver *self;
1184 self = (InternalFolderObserver *) object;
1185 g_object_unref (self->new_headers);
1187 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1190 tny_folder_observer_init (TnyFolderObserverIface *iface)
1192 iface->update = internal_folder_observer_update;
1195 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1197 GObjectClass *object_class;
1199 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1200 object_class = (GObjectClass*) klass;
1201 object_class->finalize = internal_folder_observer_finalize;
1206 ModestMailOperation *mail_op;
1207 gchar *account_name;
1208 UpdateAccountCallback callback;
1213 TnyFolderObserver *inbox_observer;
1214 RetrieveAllCallback retrieve_all_cb;
1215 gboolean interactive;
1216 } UpdateAccountInfo;
1220 destroy_update_account_info (UpdateAccountInfo *info)
1222 g_free (info->account_name);
1223 g_object_unref (info->folders);
1224 g_object_unref (info->mail_op);
1225 g_slice_free (UpdateAccountInfo, info);
1229 update_account_get_msg_async_cb (TnyFolder *folder,
1235 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1237 /* Just delete the helper. Don't do anything with the new
1238 msg. There is also no need to check for errors */
1239 g_object_unref (msg_info->mail_op);
1240 g_object_unref (msg_info->header);
1241 g_slice_free (GetMsgInfo, msg_info);
1245 update_account_notify_user_and_free (UpdateAccountInfo *info,
1246 TnyList *new_headers)
1248 /* Set the account back to not busy */
1249 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1250 info->account_name, FALSE);
1254 info->callback (info->mail_op, new_headers, info->user_data);
1256 /* Mail operation end */
1257 modest_mail_operation_notify_end (info->mail_op);
1261 g_object_unref (new_headers);
1262 destroy_update_account_info (info);
1266 inbox_refreshed_cb (TnyFolder *inbox,
1271 UpdateAccountInfo *info;
1272 ModestMailOperationPrivate *priv;
1273 TnyIterator *new_headers_iter;
1274 GPtrArray *new_headers_array = NULL;
1275 gint max_size, retrieve_limit, i;
1276 ModestAccountMgr *mgr;
1277 ModestAccountRetrieveType retrieve_type;
1278 TnyList *new_headers = NULL;
1279 gboolean headers_only, ignore_limit;
1280 TnyTransportAccount *transport_account = NULL;
1282 info = (UpdateAccountInfo *) user_data;
1283 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1284 mgr = modest_runtime_get_account_mgr ();
1286 if (canceled || err) {
1287 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1289 priv->error = g_error_copy (err);
1291 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1292 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1294 /* Notify the user about the error and then exit */
1295 update_account_notify_user_and_free (info, NULL);
1300 /* Try to send anyway */
1304 /* Get the message max size */
1305 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1306 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1308 max_size = G_MAXINT;
1310 max_size = max_size * KB;
1312 /* Create the new headers array. We need it to sort the
1313 new headers by date */
1314 new_headers_array = g_ptr_array_new ();
1315 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1316 while (!tny_iterator_is_done (new_headers_iter)) {
1317 TnyHeader *header = NULL;
1319 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1320 /* Apply per-message size limits */
1321 if (tny_header_get_message_size (header) < max_size)
1322 g_ptr_array_add (new_headers_array, g_object_ref (header));
1324 g_object_unref (header);
1325 tny_iterator_next (new_headers_iter);
1327 g_object_unref (new_headers_iter);
1328 tny_folder_remove_observer (inbox, info->inbox_observer);
1329 g_object_unref (info->inbox_observer);
1330 info->inbox_observer = NULL;
1332 /* Update the last updated key, even if we don't have to get new headers */
1333 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1335 if (new_headers_array->len == 0)
1338 /* Get per-account message amount retrieval limit */
1339 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1340 if (retrieve_limit == 0)
1341 retrieve_limit = G_MAXINT;
1343 /* Get per-account retrieval type */
1344 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1345 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1348 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1350 /* Ask the users if they want to retrieve all the messages
1351 even though the limit was exceeded */
1352 ignore_limit = FALSE;
1353 if (new_headers_array->len > retrieve_limit) {
1354 /* Ask the user if a callback has been specified and
1355 if the mail operation has a source (this means that
1356 was invoked by the user and not automatically by a
1358 if (info->retrieve_all_cb && priv->source)
1359 ignore_limit = info->retrieve_all_cb (priv->source,
1360 new_headers_array->len,
1364 if (!headers_only) {
1366 const gint msg_list_size = compute_message_array_size (new_headers_array);
1370 priv->total = new_headers_array->len;
1372 priv->total = MIN (new_headers_array->len, retrieve_limit);
1373 while (msg_num < priv->total) {
1374 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1375 TnyFolder *folder = tny_header_get_folder (header);
1376 GetMsgInfo *msg_info;
1378 /* Create the message info */
1379 msg_info = g_slice_new0 (GetMsgInfo);
1380 msg_info->mail_op = g_object_ref (info->mail_op);
1381 msg_info->header = g_object_ref (header);
1382 msg_info->total_bytes = msg_list_size;
1384 /* Get message in an async way */
1385 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1386 get_msg_status_cb, msg_info);
1388 g_object_unref (folder);
1394 /* Copy the headers to a list and free the array */
1395 new_headers = tny_simple_list_new ();
1396 for (i=0; i < new_headers_array->len; i++) {
1397 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1398 tny_list_append (new_headers, G_OBJECT (header));
1400 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1401 g_ptr_array_free (new_headers_array, FALSE);
1404 /* Get the transport account */
1405 transport_account = (TnyTransportAccount *)
1406 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1407 info->account_name);
1409 if (transport_account) {
1410 ModestTnySendQueue *send_queue;
1414 send_queue = modest_runtime_get_send_queue (transport_account);
1415 g_object_unref (transport_account);
1417 /* Get outbox folder */
1418 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1419 if (outbox) { /* this could fail in some cases */
1420 num_messages = tny_folder_get_all_count (outbox);
1421 g_object_unref (outbox);
1423 g_warning ("%s: could not get outbox", __FUNCTION__);
1427 if (num_messages != 0) {
1428 /* Reenable suspended items */
1429 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1432 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1433 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1438 /* Check if the operation was a success */
1440 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1442 /* Call the user callback and free */
1443 update_account_notify_user_and_free (info, new_headers);
1447 recurse_folders_async_cb (TnyFolderStore *folder_store,
1453 UpdateAccountInfo *info;
1454 ModestMailOperationPrivate *priv;
1456 info = (UpdateAccountInfo *) user_data;
1457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1459 if (err || canceled) {
1460 /* If the error was previosly set by another callback
1461 don't set it again */
1463 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1465 priv->error = g_error_copy (err);
1467 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1468 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1472 /* We're not getting INBOX children if we don't want to poke all */
1473 TnyIterator *iter = tny_list_create_iterator (list);
1474 while (!tny_iterator_is_done (iter)) {
1475 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1477 /* Add to the list of all folders */
1478 tny_list_append (info->folders, (GObject *) folder);
1480 if (info->poke_all) {
1481 TnyList *folders = tny_simple_list_new ();
1482 /* Add pending call */
1483 info->pending_calls++;
1485 tny_folder_store_get_folders_async (folder, folders, NULL,
1486 recurse_folders_async_cb,
1488 g_object_unref (folders);
1491 g_object_unref (G_OBJECT (folder));
1493 tny_iterator_next (iter);
1495 g_object_unref (G_OBJECT (iter));
1498 /* Remove my own pending call */
1499 info->pending_calls--;
1501 /* This means that we have all the folders */
1502 if (info->pending_calls == 0) {
1503 TnyIterator *iter_all_folders;
1504 TnyFolder *inbox = NULL;
1506 /* If there was any error do not continue */
1508 update_account_notify_user_and_free (info, NULL);
1512 iter_all_folders = tny_list_create_iterator (info->folders);
1514 /* Do a poke status over all folders */
1515 while (!tny_iterator_is_done (iter_all_folders) &&
1516 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1517 TnyFolder *folder = NULL;
1519 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1521 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1522 /* Get a reference to the INBOX */
1523 inbox = g_object_ref (folder);
1525 /* Issue a poke status over the folder */
1527 tny_folder_poke_status (folder);
1530 /* Free and go to next */
1531 g_object_unref (folder);
1532 tny_iterator_next (iter_all_folders);
1534 g_object_unref (iter_all_folders);
1536 /* Refresh the INBOX */
1538 /* Refresh the folder. Our observer receives
1539 * the new emails during folder refreshes, so
1540 * we can use observer->new_headers
1542 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1543 tny_folder_add_observer (inbox, info->inbox_observer);
1545 /* Refresh the INBOX */
1546 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1547 g_object_unref (inbox);
1549 /* We could not perform the inbox refresh but
1550 we'll try to send mails anyway */
1551 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1557 modest_mail_operation_update_account (ModestMailOperation *self,
1558 const gchar *account_name,
1560 gboolean interactive,
1561 RetrieveAllCallback retrieve_all_cb,
1562 UpdateAccountCallback callback,
1565 UpdateAccountInfo *info = NULL;
1566 ModestMailOperationPrivate *priv = NULL;
1567 ModestTnyAccountStore *account_store = NULL;
1569 ModestMailOperationState *state;
1571 /* Init mail operation */
1572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1575 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1576 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1578 /* Get the store account */
1579 account_store = modest_runtime_get_account_store ();
1581 modest_tny_account_store_get_server_account (account_store,
1583 TNY_ACCOUNT_TYPE_STORE);
1585 /* The above function could return NULL */
1586 if (!priv->account) {
1587 /* Check if the operation was a success */
1588 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1589 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1591 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1593 /* Call the user callback */
1595 callback (self, NULL, user_data);
1597 /* Notify about operation end */
1598 modest_mail_operation_notify_end (self);
1603 /* We have once seen priv->account getting finalized during this code,
1604 * therefore adding a reference (bug #82296) */
1606 g_object_ref (priv->account);
1608 /* Create the helper object */
1609 info = g_slice_new0 (UpdateAccountInfo);
1610 info->pending_calls = 1;
1611 info->folders = tny_simple_list_new ();
1612 info->mail_op = g_object_ref (self);
1613 info->poke_all = poke_all;
1614 info->interactive = interactive;
1615 info->account_name = g_strdup (account_name);
1616 info->callback = callback;
1617 info->user_data = user_data;
1618 info->retrieve_all_cb = retrieve_all_cb;
1620 /* Set account busy */
1621 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1622 modest_mail_operation_notify_start (self);
1624 /* notify about the start of the operation */
1625 state = modest_mail_operation_clone_state (self);
1629 /* Start notifying progress */
1630 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1631 g_slice_free (ModestMailOperationState, state);
1633 /* Get all folders and continue in the callback */
1634 folders = tny_simple_list_new ();
1635 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1637 recurse_folders_async_cb,
1639 g_object_unref (folders);
1641 g_object_unref (priv->account);
1646 * Used to notify the queue from the main
1647 * loop. We call it inside an idle call to achieve that
1650 idle_notify_queue (gpointer data)
1652 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1654 gdk_threads_enter ();
1655 modest_mail_operation_notify_end (mail_op);
1656 gdk_threads_leave ();
1657 g_object_unref (mail_op);
1663 compare_headers_by_date (gconstpointer a,
1666 TnyHeader **header1, **header2;
1667 time_t sent1, sent2;
1669 header1 = (TnyHeader **) a;
1670 header2 = (TnyHeader **) b;
1672 sent1 = tny_header_get_date_sent (*header1);
1673 sent2 = tny_header_get_date_sent (*header2);
1675 /* We want the most recent ones (greater time_t) at the
1684 /* ******************************************************************* */
1685 /* ************************** STORE ACTIONS ************************* */
1686 /* ******************************************************************* */
1689 ModestMailOperation *mail_op;
1690 CreateFolderUserCallback callback;
1696 create_folder_cb (TnyFolderStore *parent_folder,
1698 TnyFolder *new_folder,
1702 ModestMailOperationPrivate *priv;
1703 CreateFolderInfo *info;
1705 info = (CreateFolderInfo *) user_data;
1706 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1708 if (canceled || err) {
1709 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1711 priv->error = g_error_copy (err);
1713 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1714 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1717 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1720 /* The user will unref the new_folder */
1722 info->callback (info->mail_op, parent_folder,
1723 new_folder, info->user_data);
1725 /* Notify about operation end */
1726 modest_mail_operation_notify_end (info->mail_op);
1729 g_object_unref (info->mail_op);
1730 g_slice_free (CreateFolderInfo, info);
1734 modest_mail_operation_create_folder (ModestMailOperation *self,
1735 TnyFolderStore *parent,
1737 CreateFolderUserCallback callback,
1740 ModestMailOperationPrivate *priv;
1742 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1743 g_return_if_fail (name);
1745 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1746 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1747 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1748 g_object_ref (parent) :
1749 modest_tny_folder_get_account (TNY_FOLDER (parent));
1751 /* Check for already existing folder */
1752 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1755 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1756 _CS("ckdg_ib_folder_already_exists"));
1760 if (TNY_IS_FOLDER (parent)) {
1761 /* Check folder rules */
1762 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1763 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1764 /* Set status failed and set an error */
1765 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1766 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1767 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1768 _("mail_in_ui_folder_create_error"));
1772 if (!strcmp (name, " ") || strchr (name, '/')) {
1773 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1774 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1775 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1776 _("mail_in_ui_folder_create_error"));
1780 CreateFolderInfo *info;
1782 info = g_slice_new0 (CreateFolderInfo);
1783 info->mail_op = g_object_ref (self);
1784 info->callback = callback;
1785 info->user_data = user_data;
1787 modest_mail_operation_notify_start (self);
1789 /* Create the folder */
1790 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1793 /* Call the user callback anyway */
1795 callback (self, parent, NULL, user_data);
1796 /* Notify about operation end */
1797 modest_mail_operation_notify_end (self);
1802 modest_mail_operation_remove_folder (ModestMailOperation *self,
1804 gboolean remove_to_trash)
1806 ModestMailOperationPrivate *priv;
1807 ModestTnyFolderRules rules;
1809 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1810 g_return_if_fail (TNY_IS_FOLDER (folder));
1812 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1814 /* Check folder rules */
1815 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1816 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1817 /* Set status failed and set an error */
1818 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1819 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1820 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1821 _("mail_in_ui_folder_delete_error"));
1825 /* Get the account */
1826 priv->account = modest_tny_folder_get_account (folder);
1827 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1829 /* Delete folder or move to trash */
1830 if (remove_to_trash) {
1831 TnyFolder *trash_folder = NULL;
1832 trash_folder = modest_tny_account_get_special_folder (priv->account,
1833 TNY_FOLDER_TYPE_TRASH);
1834 /* TODO: error_handling */
1836 modest_mail_operation_notify_start (self);
1837 modest_mail_operation_xfer_folder (self, folder,
1838 TNY_FOLDER_STORE (trash_folder),
1840 g_object_unref (trash_folder);
1842 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1845 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1847 modest_mail_operation_notify_start (self);
1848 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1849 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1852 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1854 g_object_unref (parent);
1856 g_warning ("%s: could not get parent folder", __FUNCTION__);
1860 /* Notify about operation end */
1861 modest_mail_operation_notify_end (self);
1865 transfer_folder_status_cb (GObject *obj,
1869 ModestMailOperation *self;
1870 ModestMailOperationPrivate *priv;
1871 ModestMailOperationState *state;
1872 XFerFolderAsyncHelper *helper;
1874 g_return_if_fail (status != NULL);
1876 /* Show only the status information we want */
1877 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
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);
1886 priv->done = status->position;
1887 priv->total = status->of_total;
1889 state = modest_mail_operation_clone_state (self);
1891 /* This is not a GDK lock because we are a Tinymail callback
1892 * which is already GDK locked by Tinymail */
1894 /* no gdk_threads_enter (), CHECKED */
1896 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1898 /* no gdk_threads_leave (), CHECKED */
1900 g_slice_free (ModestMailOperationState, state);
1905 transfer_folder_cb (TnyFolder *folder,
1907 TnyFolderStore *into,
1908 TnyFolder *new_folder,
1912 XFerFolderAsyncHelper *helper;
1913 ModestMailOperation *self = NULL;
1914 ModestMailOperationPrivate *priv = NULL;
1916 helper = (XFerFolderAsyncHelper *) user_data;
1917 g_return_if_fail (helper != NULL);
1919 self = helper->mail_op;
1920 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1923 priv->error = g_error_copy (err);
1925 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1926 } else if (cancelled) {
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1928 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1929 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1930 _("Transference of %s was cancelled."),
1931 tny_folder_get_name (folder));
1934 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1937 /* Notify about operation end */
1938 modest_mail_operation_notify_end (self);
1940 /* If user defined callback function was defined, call it */
1941 if (helper->user_callback) {
1943 /* This is not a GDK lock because we are a Tinymail callback
1944 * which is already GDK locked by Tinymail */
1946 /* no gdk_threads_enter (), CHECKED */
1947 helper->user_callback (self, new_folder, helper->user_data);
1948 /* no gdk_threads_leave () , CHECKED */
1952 g_object_unref (helper->mail_op);
1953 g_slice_free (XFerFolderAsyncHelper, helper);
1958 * This function checks if the new name is a valid name for our local
1959 * folders account. The new name could not be the same than then name
1960 * of any of the mandatory local folders
1962 * We can not rely on tinymail because tinymail does not check the
1963 * name of the virtual folders that the account could have in the case
1964 * that we're doing a rename (because it directly calls Camel which
1965 * knows nothing about our virtual folders).
1967 * In the case of an actual copy/move (i.e. move/copy a folder between
1968 * accounts) tinymail uses the tny_folder_store_create_account which
1969 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1970 * checks the new name of the folder, so this call in that case
1971 * wouldn't be needed. *But* NOTE that if tinymail changes its
1972 * implementation (if folder transfers within the same account is no
1973 * longer implemented as a rename) this call will allow Modest to work
1976 * If the new name is not valid, this function will set the status to
1977 * failed and will set also an error in the mail operation
1980 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1981 TnyFolderStore *into,
1982 const gchar *new_name)
1984 if (TNY_IS_ACCOUNT (into) &&
1985 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1986 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1989 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1990 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1991 _CS("ckdg_ib_folder_already_exists"));
1998 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2000 TnyFolderStore *parent,
2001 gboolean delete_original,
2002 XferFolderAsyncUserCallback user_callback,
2005 ModestMailOperationPrivate *priv = NULL;
2006 ModestTnyFolderRules parent_rules = 0, rules;
2007 XFerFolderAsyncHelper *helper = NULL;
2008 const gchar *folder_name = NULL;
2009 const gchar *error_msg;
2011 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2012 g_return_if_fail (TNY_IS_FOLDER (folder));
2013 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2015 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2016 folder_name = tny_folder_get_name (folder);
2018 /* Set the error msg */
2019 error_msg = _("mail_in_ui_folder_move_target_error");
2021 /* Get account and set it into mail_operation */
2022 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2023 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2024 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2026 /* Get folder rules */
2027 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2028 if (TNY_IS_FOLDER (parent))
2029 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2031 /* Apply operation constraints */
2032 if ((gpointer) parent == (gpointer) folder ||
2033 (!TNY_IS_FOLDER_STORE (parent)) ||
2034 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2037 } else if (TNY_IS_FOLDER (parent) &&
2038 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2042 } else if (TNY_IS_FOLDER (parent) &&
2043 TNY_IS_FOLDER_STORE (folder) &&
2044 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2045 TNY_FOLDER_STORE (folder))) {
2046 /* Do not move a parent into a child */
2048 } else if (TNY_IS_FOLDER_STORE (parent) &&
2049 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2050 /* Check that the new folder name is not used by any
2053 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2054 /* Check that the new folder name is not used by any
2055 special local folder */
2058 /* Create the helper */
2059 helper = g_slice_new0 (XFerFolderAsyncHelper);
2060 helper->mail_op = g_object_ref (self);
2061 helper->user_callback = user_callback;
2062 helper->user_data = user_data;
2064 /* Move/Copy folder */
2065 modest_mail_operation_notify_start (self);
2066 tny_folder_copy_async (folder,
2068 tny_folder_get_name (folder),
2071 transfer_folder_status_cb,
2077 /* Set status failed and set an error */
2078 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2079 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2080 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2083 /* Call the user callback if exists */
2085 user_callback (self, NULL, user_data);
2087 /* Notify the queue */
2088 modest_mail_operation_notify_end (self);
2092 modest_mail_operation_rename_folder (ModestMailOperation *self,
2095 XferFolderAsyncUserCallback user_callback,
2098 ModestMailOperationPrivate *priv;
2099 ModestTnyFolderRules rules;
2100 XFerFolderAsyncHelper *helper;
2102 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2103 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2104 g_return_if_fail (name);
2106 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2108 /* Get account and set it into mail_operation */
2109 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2110 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2112 /* Check folder rules */
2113 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2114 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2116 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2119 TnyFolderStore *into;
2121 into = tny_folder_get_folder_store (folder);
2123 /* Check that the new folder name is not used by any
2124 special local folder */
2125 if (new_name_valid_if_local_account (priv, into, name)) {
2126 /* Create the helper */
2127 helper = g_slice_new0 (XFerFolderAsyncHelper);
2128 helper->mail_op = g_object_ref(self);
2129 helper->user_callback = user_callback;
2130 helper->user_data = user_data;
2132 /* Rename. Camel handles folder subscription/unsubscription */
2133 modest_mail_operation_notify_start (self);
2134 tny_folder_copy_async (folder, into, name, TRUE,
2136 transfer_folder_status_cb,
2138 g_object_unref (into);
2140 g_object_unref (into);
2147 /* Set status failed and set an error */
2148 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2149 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2150 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2151 _("FIXME: unable to rename"));
2154 user_callback (self, NULL, user_data);
2156 /* Notify about operation end */
2157 modest_mail_operation_notify_end (self);
2160 /* ******************************************************************* */
2161 /* ************************** MSG ACTIONS ************************* */
2162 /* ******************************************************************* */
2165 modest_mail_operation_get_msg (ModestMailOperation *self,
2167 GetMsgAsyncUserCallback user_callback,
2170 GetMsgInfo *helper = NULL;
2172 ModestMailOperationPrivate *priv;
2174 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2175 g_return_if_fail (TNY_IS_HEADER (header));
2177 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2178 folder = tny_header_get_folder (header);
2180 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2184 /* Get account and set it into mail_operation */
2185 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2187 /* Check for cached messages */
2188 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2191 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2193 /* Create the helper */
2194 helper = g_slice_new0 (GetMsgInfo);
2195 helper->header = g_object_ref (header);
2196 helper->mail_op = g_object_ref (self);
2197 helper->user_callback = user_callback;
2198 helper->user_data = user_data;
2199 helper->destroy_notify = NULL;
2200 helper->last_total_bytes = 0;
2201 helper->sum_total_bytes = 0;
2202 helper->total_bytes = tny_header_get_message_size (header);
2203 helper->more_msgs = NULL;
2205 modest_mail_operation_notify_start (self);
2207 /* notify about the start of the operation */
2208 ModestMailOperationState *state;
2209 state = modest_mail_operation_clone_state (self);
2212 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2215 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2217 g_object_unref (G_OBJECT (folder));
2221 get_msg_status_cb (GObject *obj,
2225 GetMsgInfo *helper = NULL;
2227 g_return_if_fail (status != NULL);
2229 /* Show only the status information we want */
2230 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2233 helper = (GetMsgInfo *) user_data;
2234 g_return_if_fail (helper != NULL);
2236 /* Notify progress */
2237 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2238 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2242 get_msg_async_cb (TnyFolder *folder,
2248 GetMsgInfo *info = NULL;
2249 ModestMailOperationPrivate *priv = NULL;
2252 info = (GetMsgInfo *) user_data;
2254 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2257 if (info->more_msgs) {
2258 tny_iterator_next (info->more_msgs);
2259 finished = (tny_iterator_is_done (info->more_msgs));
2261 finished = (priv->done == priv->total) ? TRUE : FALSE;
2264 /* If canceled by the user, ignore the error given by Tinymail */
2268 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2270 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2272 priv->error = g_error_copy ((const GError *) err);
2273 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2276 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2277 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2280 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2281 /* Set the success status before calling the user callback */
2282 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2286 /* Call the user callback */
2287 if (info->user_callback)
2288 info->user_callback (info->mail_op, info->header, canceled,
2289 msg, err, info->user_data);
2291 /* Notify about operation end if this is the last callback */
2293 /* Free user data */
2294 if (info->destroy_notify)
2295 info->destroy_notify (info->user_data);
2297 /* Notify about operation end */
2298 modest_mail_operation_notify_end (info->mail_op);
2301 if (info->more_msgs)
2302 g_object_unref (info->more_msgs);
2303 g_object_unref (info->header);
2304 g_object_unref (info->mail_op);
2305 g_slice_free (GetMsgInfo, info);
2306 } else if (info->more_msgs) {
2307 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2308 TnyFolder *folder = tny_header_get_folder (header);
2310 g_object_unref (info->header);
2311 info->header = g_object_ref (header);
2313 /* Retrieve the next message */
2314 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2316 g_object_unref (header);
2317 g_object_unref (folder);
2319 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2324 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2325 TnyList *header_list,
2326 GetMsgAsyncUserCallback user_callback,
2328 GDestroyNotify notify)
2330 ModestMailOperationPrivate *priv = NULL;
2332 TnyIterator *iter = NULL;
2333 gboolean has_uncached_messages;
2335 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2337 /* Init mail operation */
2338 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2339 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2341 priv->total = tny_list_get_length(header_list);
2343 /* Check uncached messages */
2344 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2345 !has_uncached_messages && !tny_iterator_is_done (iter);
2346 tny_iterator_next (iter)) {
2349 header = (TnyHeader *) tny_iterator_get_current (iter);
2350 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2351 has_uncached_messages = TRUE;
2352 g_object_unref (header);
2354 g_object_unref (iter);
2355 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2357 /* Get account and set it into mail_operation */
2358 if (tny_list_get_length (header_list) >= 1) {
2359 TnyIterator *iterator = tny_list_create_iterator (header_list);
2360 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2362 TnyFolder *folder = tny_header_get_folder (header);
2364 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2365 g_object_unref (folder);
2367 g_object_unref (header);
2369 g_object_unref (iterator);
2372 msg_list_size = compute_message_list_size (header_list);
2374 modest_mail_operation_notify_start (self);
2375 iter = tny_list_create_iterator (header_list);
2376 if (!tny_iterator_is_done (iter)) {
2377 /* notify about the start of the operation */
2378 ModestMailOperationState *state;
2379 state = modest_mail_operation_clone_state (self);
2382 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2385 GetMsgInfo *msg_info = NULL;
2386 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2387 TnyFolder *folder = tny_header_get_folder (header);
2389 /* Create the message info */
2390 msg_info = g_slice_new0 (GetMsgInfo);
2391 msg_info->mail_op = g_object_ref (self);
2392 msg_info->header = g_object_ref (header);
2393 msg_info->more_msgs = g_object_ref (iter);
2394 msg_info->user_callback = user_callback;
2395 msg_info->user_data = user_data;
2396 msg_info->destroy_notify = notify;
2397 msg_info->last_total_bytes = 0;
2398 msg_info->sum_total_bytes = 0;
2399 msg_info->total_bytes = msg_list_size;
2401 /* The callback will call it per each header */
2402 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2404 /* Free and go on */
2405 g_object_unref (header);
2406 g_object_unref (folder);
2407 g_slice_free (ModestMailOperationState, state);
2409 g_object_unref (iter);
2414 remove_msgs_async_cb (TnyFolder *folder,
2419 gboolean expunge, leave_on_server;
2420 const gchar *account_name;
2422 TnyAccount *account;
2423 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2424 ModestMailOperation *self;
2425 ModestMailOperationPrivate *priv;
2427 self = (ModestMailOperation *) user_data;
2428 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2430 if (canceled || err) {
2431 /* If canceled by the user, ignore the error given by Tinymail */
2433 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2435 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2436 priv->error = g_error_copy ((const GError *) err);
2437 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2440 modest_mail_operation_notify_end (self);
2441 g_object_unref (self);
2445 account = tny_folder_get_account (folder);
2446 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2448 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2450 proto = tny_account_get_proto (account);
2451 g_object_unref (account);
2454 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2456 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2457 modest_tny_folder_is_remote_folder (folder) == FALSE)
2463 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2468 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2470 gboolean remove_to_trash /*ignored*/)
2472 TnyFolder *folder = NULL;
2473 ModestMailOperationPrivate *priv;
2474 TnyIterator *iter = NULL;
2475 TnyHeader *header = NULL;
2476 TnyList *remove_headers = NULL;
2477 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2479 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2480 g_return_if_fail (TNY_IS_LIST (headers));
2482 if (remove_to_trash)
2483 g_warning ("remove to trash is not implemented");
2485 if (tny_list_get_length(headers) == 0) {
2486 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2487 goto cleanup; /* nothing to do */
2490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2491 remove_headers = g_object_ref(headers);
2493 /* Get folder from first header and sync it */
2494 iter = tny_list_create_iterator (headers);
2495 header = TNY_HEADER (tny_iterator_get_current (iter));
2497 folder = tny_header_get_folder (header);
2498 if (!TNY_IS_FOLDER(folder)) {
2499 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2503 /* Don't remove messages that are being sent */
2504 if (modest_tny_folder_is_local_folder (folder)) {
2505 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2507 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2508 TnyTransportAccount *traccount = NULL;
2509 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2510 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2512 ModestTnySendQueueStatus status;
2513 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2514 TnyIterator *iter = tny_list_create_iterator(headers);
2515 g_object_unref(remove_headers);
2516 remove_headers = TNY_LIST(tny_simple_list_new());
2517 while (!tny_iterator_is_done(iter)) {
2519 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2520 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2521 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2522 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2523 tny_list_append(remove_headers, G_OBJECT(hdr));
2525 g_object_unref(hdr);
2527 tny_iterator_next(iter);
2529 g_object_unref(iter);
2530 g_object_unref(traccount);
2534 /* Get account and set it into mail_operation */
2535 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2536 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2537 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2539 /* remove message from folder */
2540 modest_mail_operation_notify_start (self);
2541 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2542 NULL, g_object_ref (self));
2546 g_object_unref (remove_headers);
2548 g_object_unref (header);
2550 g_object_unref (iter);
2552 g_object_unref (folder);
2556 notify_progress_of_multiple_messages (ModestMailOperation *self,
2558 gint *last_total_bytes,
2559 gint *sum_total_bytes,
2561 gboolean increment_done)
2563 ModestMailOperationPrivate *priv;
2564 ModestMailOperationState *state;
2565 gboolean is_num_bytes = FALSE;
2567 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2569 /* We know that tinymail sends us information about
2570 * transferred bytes with this particular message
2572 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2573 * I just added the 'if' so we don't get runtime warning)
2575 if (status->message)
2576 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2578 state = modest_mail_operation_clone_state (self);
2579 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2580 /* We know that we're in a different message when the
2581 total number of bytes to transfer is different. Of
2582 course it could fail if we're transferring messages
2583 of the same size, but this is a workarround */
2584 if (status->of_total != *last_total_bytes) {
2585 /* We need to increment the done when there is
2586 no information about each individual
2587 message, we need to do this in message
2588 transfers, and we don't do it for getting
2592 *sum_total_bytes += *last_total_bytes;
2593 *last_total_bytes = status->of_total;
2595 state->bytes_done += status->position + *sum_total_bytes;
2596 state->bytes_total = total_bytes;
2598 /* Notify the status change. Only notify about changes
2599 referred to bytes */
2600 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2604 g_slice_free (ModestMailOperationState, state);
2608 transfer_msgs_status_cb (GObject *obj,
2612 XFerMsgsAsyncHelper *helper;
2614 g_return_if_fail (status != NULL);
2616 /* Show only the status information we want */
2617 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2620 helper = (XFerMsgsAsyncHelper *) user_data;
2621 g_return_if_fail (helper != NULL);
2623 /* Notify progress */
2624 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2625 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2630 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2632 XFerMsgsAsyncHelper *helper;
2633 ModestMailOperation *self;
2634 ModestMailOperationPrivate *priv;
2635 gboolean finished = TRUE;
2637 helper = (XFerMsgsAsyncHelper *) user_data;
2638 self = helper->mail_op;
2640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2643 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2645 priv->error = g_error_copy (err);
2647 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2648 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2649 if (helper->more_msgs) {
2650 /* We'll transfer the next message in the list */
2651 tny_iterator_next (helper->more_msgs);
2652 if (!tny_iterator_is_done (helper->more_msgs)) {
2653 GObject *next_header;
2654 g_object_unref (helper->headers);
2655 helper->headers = tny_simple_list_new ();
2656 next_header = tny_iterator_get_current (helper->more_msgs);
2657 tny_list_append (helper->headers, next_header);
2658 g_object_unref (next_header);
2664 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2670 /* Update folder counts */
2671 tny_folder_poke_status (folder);
2672 tny_folder_poke_status (helper->dest_folder);
2674 /* Notify about operation end */
2675 modest_mail_operation_notify_end (self);
2677 /* If user defined callback function was defined, call it */
2678 if (helper->user_callback) {
2679 /* This is not a GDK lock because we are a Tinymail callback and
2680 * Tinymail already acquires the Gdk lock */
2682 /* no gdk_threads_enter (), CHECKED */
2683 helper->user_callback (self, helper->user_data);
2684 /* no gdk_threads_leave (), CHECKED */
2688 if (helper->more_msgs)
2689 g_object_unref (helper->more_msgs);
2690 if (helper->headers)
2691 g_object_unref (helper->headers);
2692 if (helper->dest_folder)
2693 g_object_unref (helper->dest_folder);
2694 if (helper->mail_op)
2695 g_object_unref (helper->mail_op);
2696 g_slice_free (XFerMsgsAsyncHelper, helper);
2698 /* Transfer more messages */
2699 tny_folder_transfer_msgs_async (folder,
2701 helper->dest_folder,
2704 transfer_msgs_status_cb,
2710 compute_message_list_size (TnyList *headers)
2715 iter = tny_list_create_iterator (headers);
2716 while (!tny_iterator_is_done (iter)) {
2717 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2718 size += tny_header_get_message_size (header);
2719 g_object_unref (header);
2720 tny_iterator_next (iter);
2722 g_object_unref (iter);
2728 compute_message_array_size (GPtrArray *headers)
2733 for (i = 0; i < headers->len; i++) {
2734 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2735 size += tny_header_get_message_size (header);
2743 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2746 gboolean delete_original,
2747 XferMsgsAsyncUserCallback user_callback,
2750 ModestMailOperationPrivate *priv = NULL;
2751 TnyIterator *iter = NULL;
2752 TnyFolder *src_folder = NULL;
2753 XFerMsgsAsyncHelper *helper = NULL;
2754 TnyHeader *header = NULL;
2755 ModestTnyFolderRules rules = 0;
2756 TnyAccount *dst_account = NULL;
2757 gboolean leave_on_server;
2759 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2760 g_return_if_fail (headers && TNY_IS_LIST (headers));
2761 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2763 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2764 priv->total = tny_list_get_length (headers);
2766 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2767 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2769 /* Apply folder rules */
2770 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2771 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2772 /* Set status failed and set an error */
2773 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2774 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2775 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2776 _CS("ckct_ib_unable_to_paste_here"));
2777 /* Notify the queue */
2778 modest_mail_operation_notify_end (self);
2782 /* Get source folder */
2783 iter = tny_list_create_iterator (headers);
2784 header = TNY_HEADER (tny_iterator_get_current (iter));
2786 src_folder = tny_header_get_folder (header);
2787 g_object_unref (header);
2789 g_object_unref (iter);
2791 if (src_folder == NULL) {
2792 /* Notify the queue */
2793 modest_mail_operation_notify_end (self);
2795 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2800 /* Check folder source and destination */
2801 if (src_folder == folder) {
2802 /* Set status failed and set an error */
2803 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2804 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2805 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2806 _("mail_in_ui_folder_copy_target_error"));
2808 /* Notify the queue */
2809 modest_mail_operation_notify_end (self);
2812 g_object_unref (src_folder);
2816 /* Create the helper */
2817 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2818 helper->mail_op = g_object_ref(self);
2819 helper->dest_folder = g_object_ref(folder);
2820 helper->user_callback = user_callback;
2821 helper->user_data = user_data;
2822 helper->delete = delete_original;
2823 helper->last_total_bytes = 0;
2824 helper->sum_total_bytes = 0;
2825 helper->total_bytes = compute_message_list_size (headers);
2827 /* Get account and set it into mail_operation */
2828 priv->account = modest_tny_folder_get_account (src_folder);
2829 dst_account = modest_tny_folder_get_account (folder);
2831 if (priv->account == dst_account) {
2832 /* Transfer all messages at once using the fast
2833 * method. Note that depending on the server this
2834 * might not be that fast, and might not be
2835 * user-cancellable either */
2836 helper->headers = g_object_ref (headers);
2837 helper->more_msgs = NULL;
2839 /* Transfer messages one by one so the user can cancel
2842 helper->headers = tny_simple_list_new ();
2843 helper->more_msgs = tny_list_create_iterator (headers);
2844 hdr = tny_iterator_get_current (helper->more_msgs);
2845 tny_list_append (helper->headers, hdr);
2846 g_object_unref (hdr);
2849 /* If leave_on_server is set to TRUE then don't use
2850 delete_original, we always pass FALSE. This is because
2851 otherwise tinymail will try to sync the source folder and
2852 this could cause an error if we're offline while
2853 transferring an already downloaded message from a POP
2855 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2856 MODEST_PROTOCOL_STORE_POP) {
2857 const gchar *account_name;
2859 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2860 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2863 leave_on_server = FALSE;
2866 modest_mail_operation_notify_start (self);
2867 tny_folder_transfer_msgs_async (src_folder,
2870 (leave_on_server) ? FALSE : delete_original,
2872 transfer_msgs_status_cb,
2874 g_object_unref (src_folder);
2875 g_object_unref (dst_account);
2880 on_refresh_folder (TnyFolder *folder,
2885 RefreshAsyncHelper *helper = NULL;
2886 ModestMailOperation *self = NULL;
2887 ModestMailOperationPrivate *priv = NULL;
2889 helper = (RefreshAsyncHelper *) user_data;
2890 self = helper->mail_op;
2891 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2893 g_return_if_fail(priv!=NULL);
2896 priv->error = g_error_copy (error);
2897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2902 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2903 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2904 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2905 _("Error trying to refresh the contents of %s"),
2906 tny_folder_get_name (folder));
2910 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2913 /* Call user defined callback, if it exists */
2914 if (helper->user_callback) {
2916 /* This is not a GDK lock because we are a Tinymail callback and
2917 * Tinymail already acquires the Gdk lock */
2918 helper->user_callback (self, folder, helper->user_data);
2922 g_slice_free (RefreshAsyncHelper, helper);
2924 /* Notify about operation end */
2925 modest_mail_operation_notify_end (self);
2926 g_object_unref(self);
2930 on_refresh_folder_status_update (GObject *obj,
2934 RefreshAsyncHelper *helper = NULL;
2935 ModestMailOperation *self = NULL;
2936 ModestMailOperationPrivate *priv = NULL;
2937 ModestMailOperationState *state;
2939 g_return_if_fail (user_data != NULL);
2940 g_return_if_fail (status != NULL);
2942 /* Show only the status information we want */
2943 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2946 helper = (RefreshAsyncHelper *) user_data;
2947 self = helper->mail_op;
2948 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2950 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2952 priv->done = status->position;
2953 priv->total = status->of_total;
2955 state = modest_mail_operation_clone_state (self);
2957 /* This is not a GDK lock because we are a Tinymail callback and
2958 * Tinymail already acquires the Gdk lock */
2959 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2961 g_slice_free (ModestMailOperationState, state);
2965 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2967 RefreshAsyncUserCallback user_callback,
2970 ModestMailOperationPrivate *priv = NULL;
2971 RefreshAsyncHelper *helper = NULL;
2973 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2975 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2977 /* Get account and set it into mail_operation */
2978 priv->account = modest_tny_folder_get_account (folder);
2979 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2981 /* Create the helper */
2982 helper = g_slice_new0 (RefreshAsyncHelper);
2983 helper->mail_op = g_object_ref(self);
2984 helper->user_callback = user_callback;
2985 helper->user_data = user_data;
2987 modest_mail_operation_notify_start (self);
2989 /* notify that the operation was started */
2990 ModestMailOperationState *state;
2991 state = modest_mail_operation_clone_state (self);
2994 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2997 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2999 tny_folder_refresh_async (folder,
3001 on_refresh_folder_status_update,
3006 run_queue_stop (ModestTnySendQueue *queue,
3007 ModestMailOperation *self)
3009 ModestMailOperationPrivate *priv;
3011 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3012 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3013 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3015 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3017 modest_mail_operation_notify_end (self);
3018 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3019 g_object_unref (self);
3022 modest_mail_operation_run_queue (ModestMailOperation *self,
3023 ModestTnySendQueue *queue)
3025 ModestMailOperationPrivate *priv;
3027 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3028 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3029 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3031 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3032 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3033 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3035 modest_mail_operation_notify_start (self);
3036 g_object_ref (self);
3037 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3041 sync_folder_finish_callback (TnyFolder *self,
3047 ModestMailOperation *mail_op;
3048 ModestMailOperationPrivate *priv;
3050 mail_op = (ModestMailOperation *) user_data;
3051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3053 /* If canceled by the user, ignore the error given by Tinymail */
3055 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3057 /* If the operation was a sync then the status is
3058 failed, but if it's part of another operation then
3059 just set it as finished with errors */
3060 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3063 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3064 priv->error = g_error_copy ((const GError *) err);
3065 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3067 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3070 modest_mail_operation_notify_end (mail_op);
3071 g_object_unref (mail_op);
3075 modest_mail_operation_sync_folder (ModestMailOperation *self,
3076 TnyFolder *folder, gboolean expunge)
3078 ModestMailOperationPrivate *priv;
3080 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3081 g_return_if_fail (TNY_IS_FOLDER (folder));
3082 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3084 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3085 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3086 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3088 modest_mail_operation_notify_start (self);
3089 g_object_ref (self);
3090 tny_folder_sync_async (folder, expunge,
3091 (TnyFolderCallback) sync_folder_finish_callback,
3096 modest_mail_operation_notify_start (ModestMailOperation *self)
3098 ModestMailOperationPrivate *priv = NULL;
3100 g_return_if_fail (self);
3102 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3104 /* Ensure that all the fields are filled correctly */
3105 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3107 /* Notify the observers about the mail operation. We do not
3108 wrapp this emission because we assume that this function is
3109 always called from within the main lock */
3110 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3115 * It's used by the mail operation queue to notify the observers
3116 * attached to that signal that the operation finished. We need to use
3117 * that because tinymail does not give us the progress of a given
3118 * operation when it finishes (it directly calls the operation
3122 modest_mail_operation_notify_end (ModestMailOperation *self)
3124 ModestMailOperationPrivate *priv = NULL;
3126 g_return_if_fail (self);
3128 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3130 /* Notify the observers about the mail operation end. We do
3131 not wrapp this emission because we assume that this
3132 function is always called from within the main lock */
3133 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3135 /* Remove the error user data */
3136 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3137 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3141 modest_mail_operation_get_account (ModestMailOperation *self)
3143 ModestMailOperationPrivate *priv = NULL;
3145 g_return_val_if_fail (self, NULL);
3147 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3149 return (priv->account) ? g_object_ref (priv->account) : NULL;
3153 modest_mail_operation_noop (ModestMailOperation *self)
3155 ModestMailOperationPrivate *priv = NULL;
3157 g_return_if_fail (self);
3159 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3160 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3161 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3165 /* This mail operation does nothing actually */
3166 modest_mail_operation_notify_start (self);
3167 modest_mail_operation_notify_end (self);
3172 modest_mail_operation_to_string (ModestMailOperation *self)
3174 const gchar *type, *status, *account_id;
3175 ModestMailOperationPrivate *priv = NULL;
3177 g_return_val_if_fail (self, NULL);
3179 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3181 /* new operations don't have anything interesting */
3182 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3183 return g_strdup_printf ("%p <new operation>", self);
3185 switch (priv->op_type) {
3186 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3187 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3188 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3189 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3190 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3191 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3192 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3193 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3194 default: type = "UNEXPECTED"; break;
3197 switch (priv->status) {
3198 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3199 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3200 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3201 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3202 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3203 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3204 default: status= "UNEXPECTED"; break;
3207 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3209 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3210 priv->done, priv->total,
3211 priv->error && priv->error->message ? priv->error->message : "");