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),
510 /* Cancel the sending of the following next messages */
511 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
518 modest_mail_operation_get_task_done (ModestMailOperation *self)
520 ModestMailOperationPrivate *priv;
522 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
525 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
530 modest_mail_operation_get_task_total (ModestMailOperation *self)
532 ModestMailOperationPrivate *priv;
534 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
542 modest_mail_operation_is_finished (ModestMailOperation *self)
544 ModestMailOperationPrivate *priv;
545 gboolean retval = FALSE;
547 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
550 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
552 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
553 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
554 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
555 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
565 * Creates an image of the current state of a mail operation, the
566 * caller must free it
568 static ModestMailOperationState *
569 modest_mail_operation_clone_state (ModestMailOperation *self)
571 ModestMailOperationState *state;
572 ModestMailOperationPrivate *priv;
574 /* FIXME: this should be fixed properly
576 * in some cases, priv was NULL, so checking here to
579 g_return_val_if_fail (self, NULL);
580 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
581 g_return_val_if_fail (priv, NULL);
586 state = g_slice_new (ModestMailOperationState);
588 state->status = priv->status;
589 state->op_type = priv->op_type;
590 state->done = priv->done;
591 state->total = priv->total;
592 state->finished = modest_mail_operation_is_finished (self);
593 state->bytes_done = 0;
594 state->bytes_total = 0;
599 /* ******************************************************************* */
600 /* ************************** SEND ACTIONS ************************* */
601 /* ******************************************************************* */
604 modest_mail_operation_send_mail (ModestMailOperation *self,
605 TnyTransportAccount *transport_account,
608 TnySendQueue *send_queue = NULL;
609 ModestMailOperationPrivate *priv;
611 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
612 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
613 g_return_if_fail (msg && TNY_IS_MSG (msg));
615 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
617 /* Get account and set it into mail_operation */
618 priv->account = g_object_ref (transport_account);
619 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
623 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
624 if (!TNY_IS_SEND_QUEUE(send_queue)) {
626 g_error_free (priv->error);
629 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
630 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
631 "modest: could not find send queue for account\n");
632 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
633 modest_mail_operation_notify_end (self);
636 /* Add the msg to the queue */
637 modest_mail_operation_notify_start (self);
639 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
640 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE);
643 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
645 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
647 modest_mail_operation_notify_end (self);
654 idle_create_msg_cb (gpointer idle_data)
656 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
658 /* This is a GDK lock because we are an idle callback and
659 * info->callback can contain Gtk+ code */
661 gdk_threads_enter (); /* CHECKED */
662 info->callback (info->mail_op, info->msg, info->userdata);
664 g_object_unref (info->mail_op);
666 g_object_unref (info->msg);
667 g_slice_free (CreateMsgIdleInfo, info);
668 gdk_threads_leave (); /* CHECKED */
674 create_msg_thread (gpointer thread_data)
676 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
677 TnyMsg *new_msg = NULL;
678 ModestMailOperationPrivate *priv;
680 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
681 if (info->html_body == NULL) {
682 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
683 info->bcc, info->subject, info->plain_body,
684 info->attachments_list,
687 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
688 info->bcc, info->subject, info->html_body,
689 info->plain_body, info->attachments_list,
697 /* Set priority flags in message */
698 header = tny_msg_get_header (new_msg);
699 tny_header_set_flag (header, info->priority_flags);
701 /* Set attachment flags in message */
702 if (info->attachments_list != NULL)
703 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
705 g_object_unref (G_OBJECT(header));
707 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
709 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
710 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
711 "modest: failed to create a new msg\n");
719 g_free (info->plain_body);
720 g_free (info->html_body);
721 g_free (info->subject);
722 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
723 g_list_free (info->attachments_list);
724 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
725 g_list_free (info->images_list);
727 if (info->callback) {
728 CreateMsgIdleInfo *idle_info;
729 idle_info = g_slice_new0 (CreateMsgIdleInfo);
730 idle_info->mail_op = g_object_ref (info->mail_op);
731 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
732 idle_info->callback = info->callback;
733 idle_info->userdata = info->userdata;
734 g_idle_add (idle_create_msg_cb, idle_info);
736 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
739 g_object_unref (info->mail_op);
740 g_slice_free (CreateMsgInfo, info);
741 if (new_msg) g_object_unref(new_msg);
747 modest_mail_operation_create_msg (ModestMailOperation *self,
748 const gchar *from, const gchar *to,
749 const gchar *cc, const gchar *bcc,
750 const gchar *subject, const gchar *plain_body,
751 const gchar *html_body,
752 const GList *attachments_list,
753 const GList *images_list,
754 TnyHeaderFlags priority_flags,
755 ModestMailOperationCreateMsgCallback callback,
758 CreateMsgInfo *info = NULL;
760 info = g_slice_new0 (CreateMsgInfo);
761 info->mail_op = g_object_ref (self);
763 info->from = g_strdup (from);
764 info->to = g_strdup (to);
765 info->cc = g_strdup (cc);
766 info->bcc = g_strdup (bcc);
767 info->subject = g_strdup (subject);
768 info->plain_body = g_strdup (plain_body);
769 info->html_body = g_strdup (html_body);
770 info->attachments_list = g_list_copy ((GList *) attachments_list);
771 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
772 info->images_list = g_list_copy ((GList *) images_list);
773 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
774 info->priority_flags = priority_flags;
776 info->callback = callback;
777 info->userdata = userdata;
779 g_thread_create (create_msg_thread, info, FALSE, NULL);
784 TnyTransportAccount *transport_account;
789 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
793 ModestMailOperationPrivate *priv = NULL;
794 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
795 TnyFolder *draft_folder = NULL;
796 TnyFolder *outbox_folder = NULL;
797 TnyHeader *header = NULL;
799 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
802 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
803 modest_mail_operation_notify_end (self);
807 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
808 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
809 modest_mail_operation_notify_end (self);
813 /* Call mail operation */
814 modest_mail_operation_send_mail (self, info->transport_account, msg);
816 if (info->draft_msg != NULL) {
817 TnyList *tmp_headers = NULL;
818 TnyFolder *folder = NULL;
819 TnyFolder *src_folder = NULL;
820 TnyFolderType folder_type;
821 TnyTransportAccount *transport_account = NULL;
823 /* To remove the old mail from its source folder, we need to get the
824 * transport account of the original draft message (the transport account
825 * might have been changed by the user) */
826 header = tny_msg_get_header (info->draft_msg);
827 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
828 modest_runtime_get_account_store(), header);
829 if (transport_account == NULL)
830 transport_account = g_object_ref(info->transport_account);
831 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
832 TNY_FOLDER_TYPE_DRAFTS);
833 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
834 TNY_FOLDER_TYPE_OUTBOX);
835 g_object_unref(transport_account);
838 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
842 if (!outbox_folder) {
843 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
848 folder = tny_msg_get_folder (info->draft_msg);
849 if (folder == NULL) goto end;
850 folder_type = modest_tny_folder_guess_folder_type (folder);
852 if (folder_type == TNY_FOLDER_TYPE_INVALID)
853 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
855 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
856 src_folder = outbox_folder;
858 src_folder = draft_folder;
860 /* Note: This can fail (with a warning) if the message is not really already in a folder,
861 * because this function requires it to have a UID. */
862 tmp_headers = tny_simple_list_new ();
863 tny_list_append (tmp_headers, (GObject*) header);
864 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
865 g_object_unref (tmp_headers);
866 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /* expunge */
868 g_object_unref (folder);
873 g_object_unref (header);
875 g_object_unref (info->draft_msg);
877 g_object_unref (draft_folder);
879 g_object_unref (outbox_folder);
880 if (info->transport_account)
881 g_object_unref (info->transport_account);
882 g_slice_free (SendNewMailInfo, info);
886 modest_mail_operation_send_new_mail (ModestMailOperation *self,
887 TnyTransportAccount *transport_account,
889 const gchar *from, const gchar *to,
890 const gchar *cc, const gchar *bcc,
891 const gchar *subject, const gchar *plain_body,
892 const gchar *html_body,
893 const GList *attachments_list,
894 const GList *images_list,
895 TnyHeaderFlags priority_flags)
897 ModestMailOperationPrivate *priv = NULL;
898 SendNewMailInfo *info;
900 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
901 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
903 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
904 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
905 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
906 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
908 /* Check parametters */
910 /* Set status failed and set an error */
911 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
912 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
913 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
914 _("Error trying to send a mail. You need to set at least one recipient"));
917 info = g_slice_new0 (SendNewMailInfo);
918 info->transport_account = transport_account;
919 if (transport_account)
920 g_object_ref (transport_account);
921 info->draft_msg = draft_msg;
923 g_object_ref (draft_msg);
926 modest_mail_operation_notify_start (self);
927 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
928 attachments_list, images_list, priority_flags,
929 modest_mail_operation_send_new_mail_cb, info);
935 TnyTransportAccount *transport_account;
937 SaveToDraftstCallback callback;
941 ModestMailOperation *mailop;
942 } SaveToDraftsAddMsgInfo;
945 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
950 ModestMailOperationPrivate *priv = NULL;
951 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
952 GError *io_error = NULL;
954 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
956 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
957 io_error = priv->error;
961 g_warning ("%s: priv->error != NULL", __FUNCTION__);
962 g_error_free(priv->error);
965 priv->error = (err == NULL) ? NULL : g_error_copy(err);
967 if ((!priv->error) && (info->draft_msg != NULL)) {
968 TnyHeader *header = tny_msg_get_header (info->draft_msg);
969 TnyFolder *src_folder = tny_header_get_folder (header);
971 /* Remove the old draft */
972 tny_folder_remove_msg (src_folder, header, NULL);
974 /* Synchronize to expunge and to update the msg counts */
975 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
976 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
978 g_object_unref (G_OBJECT(header));
979 g_object_unref (G_OBJECT(src_folder));
983 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
985 g_error_free (io_error);
988 } else if (io_error) {
989 priv->error = io_error;
990 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
992 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
995 /* Call the user callback */
997 info->callback (info->mailop, info->msg, info->user_data);
999 if (info->transport_account)
1000 g_object_unref (G_OBJECT(info->transport_account));
1001 if (info->draft_msg)
1002 g_object_unref (G_OBJECT (info->draft_msg));
1004 g_object_unref (G_OBJECT(info->drafts));
1006 g_object_unref (G_OBJECT (info->msg));
1008 modest_mail_operation_notify_end (info->mailop);
1009 g_object_unref(info->mailop);
1010 g_slice_free (SaveToDraftsAddMsgInfo, info);
1015 TnyTransportAccount *transport_account;
1017 SaveToDraftstCallback callback;
1022 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1026 TnyFolder *drafts = NULL;
1027 ModestMailOperationPrivate *priv = NULL;
1028 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1030 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1033 if (!(priv->error)) {
1034 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1035 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1036 "modest: failed to create a new msg\n");
1039 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1040 TNY_FOLDER_TYPE_DRAFTS);
1041 if (!drafts && !(priv->error)) {
1042 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1043 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1044 "modest: failed to create a new msg\n");
1048 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1049 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1050 cb_info->transport_account = g_object_ref(info->transport_account);
1051 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1052 cb_info->callback = info->callback;
1053 cb_info->user_data = info->user_data;
1054 cb_info->drafts = g_object_ref(drafts);
1055 cb_info->msg = g_object_ref(msg);
1056 cb_info->mailop = g_object_ref(self);
1057 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1060 /* Call the user callback */
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1063 info->callback (self, msg, info->user_data);
1064 modest_mail_operation_notify_end (self);
1068 g_object_unref (G_OBJECT(drafts));
1069 if (info->draft_msg)
1070 g_object_unref (G_OBJECT (info->draft_msg));
1071 if (info->transport_account)
1072 g_object_unref (G_OBJECT(info->transport_account));
1073 g_slice_free (SaveToDraftsInfo, info);
1077 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1078 TnyTransportAccount *transport_account,
1080 const gchar *from, const gchar *to,
1081 const gchar *cc, const gchar *bcc,
1082 const gchar *subject, const gchar *plain_body,
1083 const gchar *html_body,
1084 const GList *attachments_list,
1085 const GList *images_list,
1086 TnyHeaderFlags priority_flags,
1087 SaveToDraftstCallback callback,
1090 ModestMailOperationPrivate *priv = NULL;
1091 SaveToDraftsInfo *info = NULL;
1093 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1094 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1098 /* Get account and set it into mail_operation */
1099 priv->account = g_object_ref (transport_account);
1100 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1102 info = g_slice_new0 (SaveToDraftsInfo);
1103 info->transport_account = g_object_ref (transport_account);
1104 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1105 info->callback = callback;
1106 info->user_data = user_data;
1108 modest_mail_operation_notify_start (self);
1109 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1110 attachments_list, images_list, priority_flags,
1111 modest_mail_operation_save_to_drafts_cb, info);
1116 ModestMailOperation *mail_op;
1117 TnyMimePart *mime_part;
1119 GetMimePartSizeCallback callback;
1121 } GetMimePartSizeInfo;
1123 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1124 /* We use this folder observer to track the headers that have been
1125 * added to a folder */
1128 TnyList *new_headers;
1129 } InternalFolderObserver;
1132 GObjectClass parent;
1133 } InternalFolderObserverClass;
1135 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1137 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1138 internal_folder_observer,
1140 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1144 foreach_add_item (gpointer header, gpointer user_data)
1146 tny_list_prepend (TNY_LIST (user_data),
1147 g_object_ref (G_OBJECT (header)));
1150 /* This is the method that looks for new messages in a folder */
1152 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1154 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1156 TnyFolderChangeChanged changed;
1158 changed = tny_folder_change_get_changed (change);
1160 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1163 /* Get added headers */
1164 list = tny_simple_list_new ();
1165 tny_folder_change_get_added_headers (change, list);
1167 /* Add them to the folder observer */
1168 tny_list_foreach (list, foreach_add_item,
1169 derived->new_headers);
1171 g_object_unref (G_OBJECT (list));
1176 internal_folder_observer_init (InternalFolderObserver *self)
1178 self->new_headers = tny_simple_list_new ();
1181 internal_folder_observer_finalize (GObject *object)
1183 InternalFolderObserver *self;
1185 self = (InternalFolderObserver *) object;
1186 g_object_unref (self->new_headers);
1188 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1191 tny_folder_observer_init (TnyFolderObserverIface *iface)
1193 iface->update = internal_folder_observer_update;
1196 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1198 GObjectClass *object_class;
1200 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1201 object_class = (GObjectClass*) klass;
1202 object_class->finalize = internal_folder_observer_finalize;
1207 ModestMailOperation *mail_op;
1208 gchar *account_name;
1209 UpdateAccountCallback callback;
1214 TnyFolderObserver *inbox_observer;
1215 RetrieveAllCallback retrieve_all_cb;
1216 gboolean interactive;
1217 } UpdateAccountInfo;
1221 destroy_update_account_info (UpdateAccountInfo *info)
1223 g_free (info->account_name);
1224 g_object_unref (info->folders);
1225 g_object_unref (info->mail_op);
1226 g_slice_free (UpdateAccountInfo, info);
1230 update_account_get_msg_async_cb (TnyFolder *folder,
1236 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1238 /* Just delete the helper. Don't do anything with the new
1239 msg. There is also no need to check for errors */
1240 g_object_unref (msg_info->mail_op);
1241 g_object_unref (msg_info->header);
1242 g_slice_free (GetMsgInfo, msg_info);
1246 update_account_notify_user_and_free (UpdateAccountInfo *info,
1247 TnyList *new_headers)
1249 /* Set the account back to not busy */
1250 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1251 info->account_name, FALSE);
1255 info->callback (info->mail_op, new_headers, info->user_data);
1257 /* Mail operation end */
1258 modest_mail_operation_notify_end (info->mail_op);
1262 g_object_unref (new_headers);
1263 destroy_update_account_info (info);
1267 inbox_refreshed_cb (TnyFolder *inbox,
1272 UpdateAccountInfo *info;
1273 ModestMailOperationPrivate *priv;
1274 TnyIterator *new_headers_iter;
1275 GPtrArray *new_headers_array = NULL;
1276 gint max_size, retrieve_limit, i;
1277 ModestAccountMgr *mgr;
1278 ModestAccountRetrieveType retrieve_type;
1279 TnyList *new_headers = NULL;
1280 gboolean headers_only, ignore_limit;
1281 TnyTransportAccount *transport_account = NULL;
1283 info = (UpdateAccountInfo *) user_data;
1284 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1285 mgr = modest_runtime_get_account_mgr ();
1287 if (canceled || err) {
1288 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1290 priv->error = g_error_copy (err);
1292 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1293 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1295 /* Notify the user about the error and then exit */
1296 update_account_notify_user_and_free (info, NULL);
1301 /* Try to send anyway */
1305 /* Get the message max size */
1306 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1307 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1309 max_size = G_MAXINT;
1311 max_size = max_size * KB;
1313 /* Create the new headers array. We need it to sort the
1314 new headers by date */
1315 new_headers_array = g_ptr_array_new ();
1316 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1317 while (!tny_iterator_is_done (new_headers_iter)) {
1318 TnyHeader *header = NULL;
1320 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1321 /* Apply per-message size limits */
1322 if (tny_header_get_message_size (header) < max_size)
1323 g_ptr_array_add (new_headers_array, g_object_ref (header));
1325 g_object_unref (header);
1326 tny_iterator_next (new_headers_iter);
1328 g_object_unref (new_headers_iter);
1329 tny_folder_remove_observer (inbox, info->inbox_observer);
1330 g_object_unref (info->inbox_observer);
1331 info->inbox_observer = NULL;
1333 /* Update the last updated key, even if we don't have to get new headers */
1334 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1336 if (new_headers_array->len == 0)
1339 /* Get per-account message amount retrieval limit */
1340 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1341 if (retrieve_limit == 0)
1342 retrieve_limit = G_MAXINT;
1344 /* Get per-account retrieval type */
1345 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1346 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1349 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1351 /* Ask the users if they want to retrieve all the messages
1352 even though the limit was exceeded */
1353 ignore_limit = FALSE;
1354 if (new_headers_array->len > retrieve_limit) {
1355 /* Ask the user if a callback has been specified and
1356 if the mail operation has a source (this means that
1357 was invoked by the user and not automatically by a
1359 if (info->retrieve_all_cb && priv->source)
1360 ignore_limit = info->retrieve_all_cb (priv->source,
1361 new_headers_array->len,
1365 if (!headers_only) {
1367 const gint msg_list_size = compute_message_array_size (new_headers_array);
1371 priv->total = new_headers_array->len;
1373 priv->total = MIN (new_headers_array->len, retrieve_limit);
1374 while (msg_num < priv->total) {
1375 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1376 TnyFolder *folder = tny_header_get_folder (header);
1377 GetMsgInfo *msg_info;
1379 /* Create the message info */
1380 msg_info = g_slice_new0 (GetMsgInfo);
1381 msg_info->mail_op = g_object_ref (info->mail_op);
1382 msg_info->header = g_object_ref (header);
1383 msg_info->total_bytes = msg_list_size;
1385 /* Get message in an async way */
1386 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1387 get_msg_status_cb, msg_info);
1389 g_object_unref (folder);
1395 /* Copy the headers to a list and free the array */
1396 new_headers = tny_simple_list_new ();
1397 for (i=0; i < new_headers_array->len; i++) {
1398 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1399 tny_list_append (new_headers, G_OBJECT (header));
1401 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1402 g_ptr_array_free (new_headers_array, FALSE);
1405 /* Get the transport account */
1406 transport_account = (TnyTransportAccount *)
1407 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1408 info->account_name);
1410 if (transport_account) {
1411 ModestTnySendQueue *send_queue;
1415 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1416 g_object_unref (transport_account);
1418 /* Get outbox folder */
1419 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1420 if (outbox) { /* this could fail in some cases */
1421 num_messages = tny_folder_get_all_count (outbox);
1422 g_object_unref (outbox);
1424 g_warning ("%s: could not get outbox", __FUNCTION__);
1428 if (num_messages != 0) {
1429 /* Reenable suspended items */
1430 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1433 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1434 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1439 /* Check if the operation was a success */
1441 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1443 /* Call the user callback and free */
1444 update_account_notify_user_and_free (info, new_headers);
1448 inbox_refresh_status_update (GObject *obj,
1452 UpdateAccountInfo *info = NULL;
1453 ModestMailOperation *self = NULL;
1454 ModestMailOperationPrivate *priv = NULL;
1455 ModestMailOperationState *state;
1457 g_return_if_fail (user_data != NULL);
1458 g_return_if_fail (status != NULL);
1460 /* Show only the status information we want */
1461 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1464 info = (UpdateAccountInfo *) user_data;
1465 self = info->mail_op;
1466 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1468 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1470 priv->done = status->position;
1471 priv->total = status->of_total;
1473 state = modest_mail_operation_clone_state (self);
1475 /* This is not a GDK lock because we are a Tinymail callback and
1476 * Tinymail already acquires the Gdk lock */
1477 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1479 g_slice_free (ModestMailOperationState, state);
1483 recurse_folders_async_cb (TnyFolderStore *folder_store,
1489 UpdateAccountInfo *info;
1490 ModestMailOperationPrivate *priv;
1492 info = (UpdateAccountInfo *) user_data;
1493 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1495 if (err || canceled) {
1496 /* If the error was previosly set by another callback
1497 don't set it again */
1499 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1501 priv->error = g_error_copy (err);
1503 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1504 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1508 /* We're not getting INBOX children if we don't want to poke all */
1509 TnyIterator *iter = tny_list_create_iterator (list);
1510 while (!tny_iterator_is_done (iter)) {
1511 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1513 /* Add to the list of all folders */
1514 tny_list_append (info->folders, (GObject *) folder);
1516 if (info->poke_all) {
1517 TnyList *folders = tny_simple_list_new ();
1518 /* Add pending call */
1519 info->pending_calls++;
1521 tny_folder_store_get_folders_async (folder, folders, NULL,
1522 recurse_folders_async_cb,
1524 g_object_unref (folders);
1527 g_object_unref (G_OBJECT (folder));
1529 tny_iterator_next (iter);
1531 g_object_unref (G_OBJECT (iter));
1534 /* Remove my own pending call */
1535 info->pending_calls--;
1537 /* This means that we have all the folders */
1538 if (info->pending_calls == 0) {
1539 TnyIterator *iter_all_folders;
1540 TnyFolder *inbox = NULL;
1542 /* If there was any error do not continue */
1544 update_account_notify_user_and_free (info, NULL);
1548 iter_all_folders = tny_list_create_iterator (info->folders);
1550 /* Do a poke status over all folders */
1551 while (!tny_iterator_is_done (iter_all_folders) &&
1552 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1553 TnyFolder *folder = NULL;
1555 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1557 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1558 /* Get a reference to the INBOX */
1559 inbox = g_object_ref (folder);
1561 /* Issue a poke status over the folder */
1563 tny_folder_poke_status (folder);
1566 /* Free and go to next */
1567 g_object_unref (folder);
1568 tny_iterator_next (iter_all_folders);
1570 g_object_unref (iter_all_folders);
1572 /* Refresh the INBOX */
1574 /* Refresh the folder. Our observer receives
1575 * the new emails during folder refreshes, so
1576 * we can use observer->new_headers
1578 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1579 tny_folder_add_observer (inbox, info->inbox_observer);
1581 /* Refresh the INBOX */
1582 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1583 g_object_unref (inbox);
1585 /* We could not perform the inbox refresh but
1586 we'll try to send mails anyway */
1587 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1593 modest_mail_operation_update_account (ModestMailOperation *self,
1594 const gchar *account_name,
1596 gboolean interactive,
1597 RetrieveAllCallback retrieve_all_cb,
1598 UpdateAccountCallback callback,
1601 UpdateAccountInfo *info = NULL;
1602 ModestMailOperationPrivate *priv = NULL;
1603 ModestTnyAccountStore *account_store = NULL;
1605 ModestMailOperationState *state;
1607 /* Init mail operation */
1608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1611 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1612 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1614 /* Get the store account */
1615 account_store = modest_runtime_get_account_store ();
1617 modest_tny_account_store_get_server_account (account_store,
1619 TNY_ACCOUNT_TYPE_STORE);
1621 /* The above function could return NULL */
1622 if (!priv->account) {
1623 /* Check if the operation was a success */
1624 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1625 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1627 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1629 /* Call the user callback */
1631 callback (self, NULL, user_data);
1633 /* Notify about operation end */
1634 modest_mail_operation_notify_end (self);
1639 /* We have once seen priv->account getting finalized during this code,
1640 * therefore adding a reference (bug #82296) */
1642 g_object_ref (priv->account);
1644 /* Create the helper object */
1645 info = g_slice_new0 (UpdateAccountInfo);
1646 info->pending_calls = 1;
1647 info->folders = tny_simple_list_new ();
1648 info->mail_op = g_object_ref (self);
1649 info->poke_all = poke_all;
1650 info->interactive = interactive;
1651 info->account_name = g_strdup (account_name);
1652 info->callback = callback;
1653 info->user_data = user_data;
1654 info->retrieve_all_cb = retrieve_all_cb;
1656 /* Set account busy */
1657 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1658 modest_mail_operation_notify_start (self);
1660 /* notify about the start of the operation */
1661 state = modest_mail_operation_clone_state (self);
1665 /* Start notifying progress */
1666 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1667 g_slice_free (ModestMailOperationState, state);
1669 /* Get all folders and continue in the callback */
1670 folders = tny_simple_list_new ();
1671 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1673 recurse_folders_async_cb,
1675 g_object_unref (folders);
1677 g_object_unref (priv->account);
1682 * Used to notify the queue from the main
1683 * loop. We call it inside an idle call to achieve that
1686 idle_notify_queue (gpointer data)
1688 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1690 gdk_threads_enter ();
1691 modest_mail_operation_notify_end (mail_op);
1692 gdk_threads_leave ();
1693 g_object_unref (mail_op);
1699 compare_headers_by_date (gconstpointer a,
1702 TnyHeader **header1, **header2;
1703 time_t sent1, sent2;
1705 header1 = (TnyHeader **) a;
1706 header2 = (TnyHeader **) b;
1708 sent1 = tny_header_get_date_sent (*header1);
1709 sent2 = tny_header_get_date_sent (*header2);
1711 /* We want the most recent ones (greater time_t) at the
1720 /* ******************************************************************* */
1721 /* ************************** STORE ACTIONS ************************* */
1722 /* ******************************************************************* */
1725 ModestMailOperation *mail_op;
1726 CreateFolderUserCallback callback;
1732 create_folder_cb (TnyFolderStore *parent_folder,
1734 TnyFolder *new_folder,
1738 ModestMailOperationPrivate *priv;
1739 CreateFolderInfo *info;
1741 info = (CreateFolderInfo *) user_data;
1742 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1744 if (canceled || err) {
1745 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1747 priv->error = g_error_copy (err);
1749 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1750 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1756 /* The user will unref the new_folder */
1758 info->callback (info->mail_op, parent_folder,
1759 new_folder, info->user_data);
1761 /* Notify about operation end */
1762 modest_mail_operation_notify_end (info->mail_op);
1765 g_object_unref (info->mail_op);
1766 g_slice_free (CreateFolderInfo, info);
1770 modest_mail_operation_create_folder (ModestMailOperation *self,
1771 TnyFolderStore *parent,
1773 CreateFolderUserCallback callback,
1776 ModestMailOperationPrivate *priv;
1778 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1779 g_return_if_fail (name);
1781 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1782 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1783 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1784 g_object_ref (parent) :
1785 modest_tny_folder_get_account (TNY_FOLDER (parent));
1787 /* Check for already existing folder */
1788 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1789 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1790 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1791 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1792 _CS("ckdg_ib_folder_already_exists"));
1796 if (TNY_IS_FOLDER (parent)) {
1797 /* Check folder rules */
1798 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1799 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1800 /* Set status failed and set an error */
1801 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1802 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1803 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1804 _("mail_in_ui_folder_create_error"));
1808 if (!strcmp (name, " ") || strchr (name, '/')) {
1809 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1810 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1811 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1812 _("mail_in_ui_folder_create_error"));
1816 CreateFolderInfo *info;
1818 info = g_slice_new0 (CreateFolderInfo);
1819 info->mail_op = g_object_ref (self);
1820 info->callback = callback;
1821 info->user_data = user_data;
1823 modest_mail_operation_notify_start (self);
1825 /* Create the folder */
1826 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1829 /* Call the user callback anyway */
1831 callback (self, parent, NULL, user_data);
1832 /* Notify about operation end */
1833 modest_mail_operation_notify_end (self);
1838 modest_mail_operation_remove_folder (ModestMailOperation *self,
1840 gboolean remove_to_trash)
1842 ModestMailOperationPrivate *priv;
1843 ModestTnyFolderRules rules;
1845 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1846 g_return_if_fail (TNY_IS_FOLDER (folder));
1848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1850 /* Check folder rules */
1851 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1852 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1853 /* Set status failed and set an error */
1854 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1855 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1856 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1857 _("mail_in_ui_folder_delete_error"));
1861 /* Get the account */
1862 priv->account = modest_tny_folder_get_account (folder);
1863 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1865 /* Delete folder or move to trash */
1866 if (remove_to_trash) {
1867 TnyFolder *trash_folder = NULL;
1868 trash_folder = modest_tny_account_get_special_folder (priv->account,
1869 TNY_FOLDER_TYPE_TRASH);
1870 /* TODO: error_handling */
1872 modest_mail_operation_notify_start (self);
1873 modest_mail_operation_xfer_folder (self, folder,
1874 TNY_FOLDER_STORE (trash_folder),
1876 g_object_unref (trash_folder);
1878 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1881 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1883 modest_mail_operation_notify_start (self);
1884 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1885 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1888 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1890 g_object_unref (parent);
1892 g_warning ("%s: could not get parent folder", __FUNCTION__);
1896 /* Notify about operation end */
1897 modest_mail_operation_notify_end (self);
1901 transfer_folder_status_cb (GObject *obj,
1905 ModestMailOperation *self;
1906 ModestMailOperationPrivate *priv;
1907 ModestMailOperationState *state;
1908 XFerFolderAsyncHelper *helper;
1910 g_return_if_fail (status != NULL);
1912 /* Show only the status information we want */
1913 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
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);
1922 priv->done = status->position;
1923 priv->total = status->of_total;
1925 state = modest_mail_operation_clone_state (self);
1927 /* This is not a GDK lock because we are a Tinymail callback
1928 * which is already GDK locked by Tinymail */
1930 /* no gdk_threads_enter (), CHECKED */
1932 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1934 /* no gdk_threads_leave (), CHECKED */
1936 g_slice_free (ModestMailOperationState, state);
1941 transfer_folder_cb (TnyFolder *folder,
1943 TnyFolderStore *into,
1944 TnyFolder *new_folder,
1948 XFerFolderAsyncHelper *helper;
1949 ModestMailOperation *self = NULL;
1950 ModestMailOperationPrivate *priv = NULL;
1952 helper = (XFerFolderAsyncHelper *) user_data;
1953 g_return_if_fail (helper != NULL);
1955 self = helper->mail_op;
1956 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1959 priv->error = g_error_copy (err);
1961 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1962 } else if (cancelled) {
1963 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1964 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1965 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1966 _("Transference of %s was cancelled."),
1967 tny_folder_get_name (folder));
1970 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1973 /* Notify about operation end */
1974 modest_mail_operation_notify_end (self);
1976 /* If user defined callback function was defined, call it */
1977 if (helper->user_callback) {
1979 /* This is not a GDK lock because we are a Tinymail callback
1980 * which is already GDK locked by Tinymail */
1982 /* no gdk_threads_enter (), CHECKED */
1983 helper->user_callback (self, new_folder, helper->user_data);
1984 /* no gdk_threads_leave () , CHECKED */
1988 g_object_unref (helper->mail_op);
1989 g_slice_free (XFerFolderAsyncHelper, helper);
1994 * This function checks if the new name is a valid name for our local
1995 * folders account. The new name could not be the same than then name
1996 * of any of the mandatory local folders
1998 * We can not rely on tinymail because tinymail does not check the
1999 * name of the virtual folders that the account could have in the case
2000 * that we're doing a rename (because it directly calls Camel which
2001 * knows nothing about our virtual folders).
2003 * In the case of an actual copy/move (i.e. move/copy a folder between
2004 * accounts) tinymail uses the tny_folder_store_create_account which
2005 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2006 * checks the new name of the folder, so this call in that case
2007 * wouldn't be needed. *But* NOTE that if tinymail changes its
2008 * implementation (if folder transfers within the same account is no
2009 * longer implemented as a rename) this call will allow Modest to work
2012 * If the new name is not valid, this function will set the status to
2013 * failed and will set also an error in the mail operation
2016 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2017 TnyFolderStore *into,
2018 const gchar *new_name)
2020 if (TNY_IS_ACCOUNT (into) &&
2021 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2022 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2024 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2025 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2026 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2027 _CS("ckdg_ib_folder_already_exists"));
2034 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2036 TnyFolderStore *parent,
2037 gboolean delete_original,
2038 XferFolderAsyncUserCallback user_callback,
2041 ModestMailOperationPrivate *priv = NULL;
2042 ModestTnyFolderRules parent_rules = 0, rules;
2043 XFerFolderAsyncHelper *helper = NULL;
2044 const gchar *folder_name = NULL;
2045 const gchar *error_msg;
2047 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2048 g_return_if_fail (TNY_IS_FOLDER (folder));
2049 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2052 folder_name = tny_folder_get_name (folder);
2054 /* Set the error msg */
2055 error_msg = _("mail_in_ui_folder_move_target_error");
2057 /* Get account and set it into mail_operation */
2058 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2059 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2060 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2062 /* Get folder rules */
2063 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2064 if (TNY_IS_FOLDER (parent))
2065 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2067 /* Apply operation constraints */
2068 if ((gpointer) parent == (gpointer) folder ||
2069 (!TNY_IS_FOLDER_STORE (parent)) ||
2070 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2073 } else if (TNY_IS_FOLDER (parent) &&
2074 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2078 } else if (TNY_IS_FOLDER (parent) &&
2079 TNY_IS_FOLDER_STORE (folder) &&
2080 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2081 TNY_FOLDER_STORE (folder))) {
2082 /* Do not move a parent into a child */
2084 } else if (TNY_IS_FOLDER_STORE (parent) &&
2085 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2086 /* Check that the new folder name is not used by any
2089 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2090 /* Check that the new folder name is not used by any
2091 special local folder */
2094 /* Create the helper */
2095 helper = g_slice_new0 (XFerFolderAsyncHelper);
2096 helper->mail_op = g_object_ref (self);
2097 helper->user_callback = user_callback;
2098 helper->user_data = user_data;
2100 /* Move/Copy folder */
2101 modest_mail_operation_notify_start (self);
2102 tny_folder_copy_async (folder,
2104 tny_folder_get_name (folder),
2107 transfer_folder_status_cb,
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,
2119 /* Call the user callback if exists */
2121 user_callback (self, NULL, user_data);
2123 /* Notify the queue */
2124 modest_mail_operation_notify_end (self);
2128 modest_mail_operation_rename_folder (ModestMailOperation *self,
2131 XferFolderAsyncUserCallback user_callback,
2134 ModestMailOperationPrivate *priv;
2135 ModestTnyFolderRules rules;
2136 XFerFolderAsyncHelper *helper;
2138 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2139 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2140 g_return_if_fail (name);
2142 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2144 /* Get account and set it into mail_operation */
2145 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2146 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2148 /* Check folder rules */
2149 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2150 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2152 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2155 TnyFolderStore *into;
2157 into = tny_folder_get_folder_store (folder);
2159 /* Check that the new folder name is not used by any
2160 special local folder */
2161 if (new_name_valid_if_local_account (priv, into, name)) {
2162 /* Create the helper */
2163 helper = g_slice_new0 (XFerFolderAsyncHelper);
2164 helper->mail_op = g_object_ref(self);
2165 helper->user_callback = user_callback;
2166 helper->user_data = user_data;
2168 /* Rename. Camel handles folder subscription/unsubscription */
2169 modest_mail_operation_notify_start (self);
2170 tny_folder_copy_async (folder, into, name, TRUE,
2172 transfer_folder_status_cb,
2174 g_object_unref (into);
2176 g_object_unref (into);
2183 /* Set status failed and set an error */
2184 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2185 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2186 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2187 _("FIXME: unable to rename"));
2190 user_callback (self, NULL, user_data);
2192 /* Notify about operation end */
2193 modest_mail_operation_notify_end (self);
2196 /* ******************************************************************* */
2197 /* ************************** MSG ACTIONS ************************* */
2198 /* ******************************************************************* */
2201 modest_mail_operation_get_msg (ModestMailOperation *self,
2203 gboolean progress_feedback,
2204 GetMsgAsyncUserCallback user_callback,
2207 GetMsgInfo *helper = NULL;
2209 ModestMailOperationPrivate *priv;
2211 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2212 g_return_if_fail (TNY_IS_HEADER (header));
2214 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2215 folder = tny_header_get_folder (header);
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2221 /* Get account and set it into mail_operation */
2222 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2224 /* Check for cached messages */
2225 if (progress_feedback) {
2226 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2227 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2229 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2231 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2234 /* Create the helper */
2235 helper = g_slice_new0 (GetMsgInfo);
2236 helper->header = g_object_ref (header);
2237 helper->mail_op = g_object_ref (self);
2238 helper->user_callback = user_callback;
2239 helper->user_data = user_data;
2240 helper->destroy_notify = NULL;
2241 helper->last_total_bytes = 0;
2242 helper->sum_total_bytes = 0;
2243 helper->total_bytes = tny_header_get_message_size (header);
2244 helper->more_msgs = NULL;
2246 modest_mail_operation_notify_start (self);
2248 /* notify about the start of the operation */
2249 ModestMailOperationState *state;
2250 state = modest_mail_operation_clone_state (self);
2253 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2256 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2258 g_object_unref (G_OBJECT (folder));
2262 get_msg_status_cb (GObject *obj,
2266 GetMsgInfo *helper = NULL;
2268 g_return_if_fail (status != NULL);
2270 /* Show only the status information we want */
2271 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2274 helper = (GetMsgInfo *) user_data;
2275 g_return_if_fail (helper != NULL);
2277 /* Notify progress */
2278 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2279 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2283 get_msg_async_cb (TnyFolder *folder,
2289 GetMsgInfo *info = NULL;
2290 ModestMailOperationPrivate *priv = NULL;
2293 info = (GetMsgInfo *) user_data;
2295 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2298 if (info->more_msgs) {
2299 tny_iterator_next (info->more_msgs);
2300 finished = (tny_iterator_is_done (info->more_msgs));
2302 finished = (priv->done == priv->total) ? TRUE : FALSE;
2305 /* If canceled by the user, ignore the error given by Tinymail */
2309 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2311 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2313 priv->error = g_error_copy ((const GError *) err);
2314 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2318 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2321 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2322 /* Set the success status before calling the user callback */
2323 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2327 /* Call the user callback */
2328 if (info->user_callback)
2329 info->user_callback (info->mail_op, info->header, canceled,
2330 msg, err, info->user_data);
2332 /* Notify about operation end if this is the last callback */
2334 /* Free user data */
2335 if (info->destroy_notify)
2336 info->destroy_notify (info->user_data);
2338 /* Notify about operation end */
2339 modest_mail_operation_notify_end (info->mail_op);
2342 if (info->more_msgs)
2343 g_object_unref (info->more_msgs);
2344 g_object_unref (info->header);
2345 g_object_unref (info->mail_op);
2346 g_slice_free (GetMsgInfo, info);
2347 } else if (info->more_msgs) {
2348 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2349 TnyFolder *folder = tny_header_get_folder (header);
2351 g_object_unref (info->header);
2352 info->header = g_object_ref (header);
2354 /* Retrieve the next message */
2355 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2357 g_object_unref (header);
2358 g_object_unref (folder);
2360 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2365 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2366 TnyList *header_list,
2367 GetMsgAsyncUserCallback user_callback,
2369 GDestroyNotify notify)
2371 ModestMailOperationPrivate *priv = NULL;
2373 TnyIterator *iter = NULL;
2374 gboolean has_uncached_messages;
2376 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2378 /* Init mail operation */
2379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2380 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2382 priv->total = tny_list_get_length(header_list);
2384 /* Check uncached messages */
2385 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2386 !has_uncached_messages && !tny_iterator_is_done (iter);
2387 tny_iterator_next (iter)) {
2390 header = (TnyHeader *) tny_iterator_get_current (iter);
2391 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2392 has_uncached_messages = TRUE;
2393 g_object_unref (header);
2395 g_object_unref (iter);
2396 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2398 /* Get account and set it into mail_operation */
2399 if (tny_list_get_length (header_list) >= 1) {
2400 TnyIterator *iterator = tny_list_create_iterator (header_list);
2401 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2403 TnyFolder *folder = tny_header_get_folder (header);
2405 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2406 g_object_unref (folder);
2408 g_object_unref (header);
2410 g_object_unref (iterator);
2413 msg_list_size = compute_message_list_size (header_list);
2415 modest_mail_operation_notify_start (self);
2416 iter = tny_list_create_iterator (header_list);
2417 if (!tny_iterator_is_done (iter)) {
2418 /* notify about the start of the operation */
2419 ModestMailOperationState *state;
2420 state = modest_mail_operation_clone_state (self);
2423 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2426 GetMsgInfo *msg_info = NULL;
2427 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2428 TnyFolder *folder = tny_header_get_folder (header);
2430 /* Create the message info */
2431 msg_info = g_slice_new0 (GetMsgInfo);
2432 msg_info->mail_op = g_object_ref (self);
2433 msg_info->header = g_object_ref (header);
2434 msg_info->more_msgs = g_object_ref (iter);
2435 msg_info->user_callback = user_callback;
2436 msg_info->user_data = user_data;
2437 msg_info->destroy_notify = notify;
2438 msg_info->last_total_bytes = 0;
2439 msg_info->sum_total_bytes = 0;
2440 msg_info->total_bytes = msg_list_size;
2442 /* The callback will call it per each header */
2443 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2445 /* Free and go on */
2446 g_object_unref (header);
2447 g_object_unref (folder);
2448 g_slice_free (ModestMailOperationState, state);
2450 g_object_unref (iter);
2455 remove_msgs_async_cb (TnyFolder *folder,
2460 gboolean expunge, leave_on_server;
2461 const gchar *account_name;
2463 TnyAccount *account;
2464 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2465 ModestMailOperation *self;
2466 ModestMailOperationPrivate *priv;
2468 self = (ModestMailOperation *) user_data;
2469 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2471 if (canceled || err) {
2472 /* If canceled by the user, ignore the error given by Tinymail */
2474 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2476 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2477 priv->error = g_error_copy ((const GError *) err);
2478 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2481 modest_mail_operation_notify_end (self);
2482 g_object_unref (self);
2486 account = tny_folder_get_account (folder);
2487 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2489 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2491 proto = tny_account_get_proto (account);
2492 g_object_unref (account);
2495 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2497 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2498 modest_tny_folder_is_remote_folder (folder) == FALSE)
2504 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2509 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2511 gboolean remove_to_trash /*ignored*/)
2513 TnyFolder *folder = NULL;
2514 ModestMailOperationPrivate *priv;
2515 TnyIterator *iter = NULL;
2516 TnyHeader *header = NULL;
2517 TnyList *remove_headers = NULL;
2518 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2520 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2521 g_return_if_fail (TNY_IS_LIST (headers));
2523 if (remove_to_trash)
2524 g_warning ("remove to trash is not implemented");
2526 if (tny_list_get_length(headers) == 0) {
2527 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2528 goto cleanup; /* nothing to do */
2531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2532 remove_headers = g_object_ref(headers);
2534 /* Get folder from first header and sync it */
2535 iter = tny_list_create_iterator (headers);
2536 header = TNY_HEADER (tny_iterator_get_current (iter));
2538 folder = tny_header_get_folder (header);
2539 if (!TNY_IS_FOLDER(folder)) {
2540 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2544 /* Don't remove messages that are being sent */
2545 if (modest_tny_folder_is_local_folder (folder)) {
2546 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2548 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2549 TnyTransportAccount *traccount = NULL;
2550 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2551 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2553 ModestTnySendQueueStatus status;
2554 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2555 TnyIterator *iter = tny_list_create_iterator(headers);
2556 g_object_unref(remove_headers);
2557 remove_headers = TNY_LIST(tny_simple_list_new());
2558 while (!tny_iterator_is_done(iter)) {
2560 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2561 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2562 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2563 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2564 tny_list_append(remove_headers, G_OBJECT(hdr));
2566 g_object_unref(hdr);
2568 tny_iterator_next(iter);
2570 g_object_unref(iter);
2571 g_object_unref(traccount);
2575 /* Get account and set it into mail_operation */
2576 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2577 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2578 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2580 /* remove message from folder */
2581 modest_mail_operation_notify_start (self);
2582 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2583 NULL, g_object_ref (self));
2587 g_object_unref (remove_headers);
2589 g_object_unref (header);
2591 g_object_unref (iter);
2593 g_object_unref (folder);
2597 notify_progress_of_multiple_messages (ModestMailOperation *self,
2599 gint *last_total_bytes,
2600 gint *sum_total_bytes,
2602 gboolean increment_done)
2604 ModestMailOperationPrivate *priv;
2605 ModestMailOperationState *state;
2606 gboolean is_num_bytes = FALSE;
2608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2610 /* We know that tinymail sends us information about
2611 * transferred bytes with this particular message
2613 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2614 * I just added the 'if' so we don't get runtime warning)
2616 if (status->message)
2617 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2619 state = modest_mail_operation_clone_state (self);
2620 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2621 /* We know that we're in a different message when the
2622 total number of bytes to transfer is different. Of
2623 course it could fail if we're transferring messages
2624 of the same size, but this is a workarround */
2625 if (status->of_total != *last_total_bytes) {
2626 /* We need to increment the done when there is
2627 no information about each individual
2628 message, we need to do this in message
2629 transfers, and we don't do it for getting
2633 *sum_total_bytes += *last_total_bytes;
2634 *last_total_bytes = status->of_total;
2636 state->bytes_done += status->position + *sum_total_bytes;
2637 state->bytes_total = total_bytes;
2639 /* Notify the status change. Only notify about changes
2640 referred to bytes */
2641 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2645 g_slice_free (ModestMailOperationState, state);
2649 transfer_msgs_status_cb (GObject *obj,
2653 XFerMsgsAsyncHelper *helper;
2655 g_return_if_fail (status != NULL);
2657 /* Show only the status information we want */
2658 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2661 helper = (XFerMsgsAsyncHelper *) user_data;
2662 g_return_if_fail (helper != NULL);
2664 /* Notify progress */
2665 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2666 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2671 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2673 XFerMsgsAsyncHelper *helper;
2674 ModestMailOperation *self;
2675 ModestMailOperationPrivate *priv;
2676 gboolean finished = TRUE;
2678 helper = (XFerMsgsAsyncHelper *) user_data;
2679 self = helper->mail_op;
2681 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2684 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2686 priv->error = g_error_copy (err);
2688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2689 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2690 if (helper->more_msgs) {
2691 /* We'll transfer the next message in the list */
2692 tny_iterator_next (helper->more_msgs);
2693 if (!tny_iterator_is_done (helper->more_msgs)) {
2694 GObject *next_header;
2695 g_object_unref (helper->headers);
2696 helper->headers = tny_simple_list_new ();
2697 next_header = tny_iterator_get_current (helper->more_msgs);
2698 tny_list_append (helper->headers, next_header);
2699 g_object_unref (next_header);
2705 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2711 /* Update folder counts */
2712 tny_folder_poke_status (folder);
2713 tny_folder_poke_status (helper->dest_folder);
2715 /* Notify about operation end */
2716 modest_mail_operation_notify_end (self);
2718 /* If user defined callback function was defined, call it */
2719 if (helper->user_callback) {
2720 /* This is not a GDK lock because we are a Tinymail callback and
2721 * Tinymail already acquires the Gdk lock */
2723 /* no gdk_threads_enter (), CHECKED */
2724 helper->user_callback (self, helper->user_data);
2725 /* no gdk_threads_leave (), CHECKED */
2729 if (helper->more_msgs)
2730 g_object_unref (helper->more_msgs);
2731 if (helper->headers)
2732 g_object_unref (helper->headers);
2733 if (helper->dest_folder)
2734 g_object_unref (helper->dest_folder);
2735 if (helper->mail_op)
2736 g_object_unref (helper->mail_op);
2737 g_slice_free (XFerMsgsAsyncHelper, helper);
2739 /* Transfer more messages */
2740 tny_folder_transfer_msgs_async (folder,
2742 helper->dest_folder,
2745 transfer_msgs_status_cb,
2751 compute_message_list_size (TnyList *headers)
2756 iter = tny_list_create_iterator (headers);
2757 while (!tny_iterator_is_done (iter)) {
2758 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2759 size += tny_header_get_message_size (header);
2760 g_object_unref (header);
2761 tny_iterator_next (iter);
2763 g_object_unref (iter);
2769 compute_message_array_size (GPtrArray *headers)
2774 for (i = 0; i < headers->len; i++) {
2775 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2776 size += tny_header_get_message_size (header);
2784 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2787 gboolean delete_original,
2788 XferMsgsAsyncUserCallback user_callback,
2791 ModestMailOperationPrivate *priv = NULL;
2792 TnyIterator *iter = NULL;
2793 TnyFolder *src_folder = NULL;
2794 XFerMsgsAsyncHelper *helper = NULL;
2795 TnyHeader *header = NULL;
2796 ModestTnyFolderRules rules = 0;
2797 TnyAccount *dst_account = NULL;
2798 gboolean leave_on_server;
2800 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2801 g_return_if_fail (headers && TNY_IS_LIST (headers));
2802 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2805 priv->total = tny_list_get_length (headers);
2807 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2808 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2810 /* Apply folder rules */
2811 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2812 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2813 /* Set status failed and set an error */
2814 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2815 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2816 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2817 _CS("ckct_ib_unable_to_paste_here"));
2818 /* Notify the queue */
2819 modest_mail_operation_notify_end (self);
2823 /* Get source folder */
2824 iter = tny_list_create_iterator (headers);
2825 header = TNY_HEADER (tny_iterator_get_current (iter));
2827 src_folder = tny_header_get_folder (header);
2828 g_object_unref (header);
2830 g_object_unref (iter);
2832 if (src_folder == NULL) {
2833 /* Notify the queue */
2834 modest_mail_operation_notify_end (self);
2836 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2841 /* Check folder source and destination */
2842 if (src_folder == folder) {
2843 /* Set status failed and set an error */
2844 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2845 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2846 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2847 _("mail_in_ui_folder_copy_target_error"));
2849 /* Notify the queue */
2850 modest_mail_operation_notify_end (self);
2853 g_object_unref (src_folder);
2857 /* Create the helper */
2858 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2859 helper->mail_op = g_object_ref(self);
2860 helper->dest_folder = g_object_ref(folder);
2861 helper->user_callback = user_callback;
2862 helper->user_data = user_data;
2863 helper->last_total_bytes = 0;
2864 helper->sum_total_bytes = 0;
2865 helper->total_bytes = compute_message_list_size (headers);
2867 /* Get account and set it into mail_operation */
2868 priv->account = modest_tny_folder_get_account (src_folder);
2869 dst_account = modest_tny_folder_get_account (folder);
2871 if (priv->account == dst_account) {
2872 /* Transfer all messages at once using the fast
2873 * method. Note that depending on the server this
2874 * might not be that fast, and might not be
2875 * user-cancellable either */
2876 helper->headers = g_object_ref (headers);
2877 helper->more_msgs = NULL;
2879 /* Transfer messages one by one so the user can cancel
2882 helper->headers = tny_simple_list_new ();
2883 helper->more_msgs = tny_list_create_iterator (headers);
2884 hdr = tny_iterator_get_current (helper->more_msgs);
2885 tny_list_append (helper->headers, hdr);
2886 g_object_unref (hdr);
2889 /* If leave_on_server is set to TRUE then don't use
2890 delete_original, we always pass FALSE. This is because
2891 otherwise tinymail will try to sync the source folder and
2892 this could cause an error if we're offline while
2893 transferring an already downloaded message from a POP
2895 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2896 MODEST_PROTOCOL_STORE_POP) {
2897 const gchar *account_name;
2899 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2900 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2903 leave_on_server = FALSE;
2906 /* Do not delete messages if leave on server is TRUE */
2907 helper->delete = (leave_on_server) ? FALSE : delete_original;
2909 modest_mail_operation_notify_start (self);
2910 tny_folder_transfer_msgs_async (src_folder,
2915 transfer_msgs_status_cb,
2917 g_object_unref (src_folder);
2918 g_object_unref (dst_account);
2923 on_refresh_folder (TnyFolder *folder,
2928 RefreshAsyncHelper *helper = NULL;
2929 ModestMailOperation *self = NULL;
2930 ModestMailOperationPrivate *priv = NULL;
2932 helper = (RefreshAsyncHelper *) user_data;
2933 self = helper->mail_op;
2934 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2936 g_return_if_fail(priv!=NULL);
2939 priv->error = g_error_copy (error);
2940 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2945 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2946 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2947 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2948 _("Error trying to refresh the contents of %s"),
2949 tny_folder_get_name (folder));
2953 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2956 /* Call user defined callback, if it exists */
2957 if (helper->user_callback) {
2959 /* This is not a GDK lock because we are a Tinymail callback and
2960 * Tinymail already acquires the Gdk lock */
2961 helper->user_callback (self, folder, helper->user_data);
2965 g_slice_free (RefreshAsyncHelper, helper);
2967 /* Notify about operation end */
2968 modest_mail_operation_notify_end (self);
2969 g_object_unref(self);
2973 on_refresh_folder_status_update (GObject *obj,
2977 RefreshAsyncHelper *helper = NULL;
2978 ModestMailOperation *self = NULL;
2979 ModestMailOperationPrivate *priv = NULL;
2980 ModestMailOperationState *state;
2982 g_return_if_fail (user_data != NULL);
2983 g_return_if_fail (status != NULL);
2985 /* Show only the status information we want */
2986 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2989 helper = (RefreshAsyncHelper *) user_data;
2990 self = helper->mail_op;
2991 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2993 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2995 priv->done = status->position;
2996 priv->total = status->of_total;
2998 state = modest_mail_operation_clone_state (self);
3000 /* This is not a GDK lock because we are a Tinymail callback and
3001 * Tinymail already acquires the Gdk lock */
3002 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3004 g_slice_free (ModestMailOperationState, state);
3008 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3010 RefreshAsyncUserCallback user_callback,
3013 ModestMailOperationPrivate *priv = NULL;
3014 RefreshAsyncHelper *helper = NULL;
3016 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3018 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3020 /* Get account and set it into mail_operation */
3021 priv->account = modest_tny_folder_get_account (folder);
3022 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3024 /* Create the helper */
3025 helper = g_slice_new0 (RefreshAsyncHelper);
3026 helper->mail_op = g_object_ref(self);
3027 helper->user_callback = user_callback;
3028 helper->user_data = user_data;
3030 modest_mail_operation_notify_start (self);
3032 /* notify that the operation was started */
3033 ModestMailOperationState *state;
3034 state = modest_mail_operation_clone_state (self);
3037 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3040 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3042 tny_folder_refresh_async (folder,
3044 on_refresh_folder_status_update,
3049 run_queue_stop (ModestTnySendQueue *queue,
3050 ModestMailOperation *self)
3052 ModestMailOperationPrivate *priv;
3054 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3055 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3056 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3058 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3060 modest_mail_operation_notify_end (self);
3061 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3062 g_object_unref (self);
3065 modest_mail_operation_run_queue (ModestMailOperation *self,
3066 ModestTnySendQueue *queue)
3068 ModestMailOperationPrivate *priv;
3070 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3071 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3072 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3074 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3075 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3076 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3078 modest_mail_operation_notify_start (self);
3079 g_object_ref (self);
3080 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3084 sync_folder_finish_callback (TnyFolder *self,
3090 ModestMailOperation *mail_op;
3091 ModestMailOperationPrivate *priv;
3093 mail_op = (ModestMailOperation *) user_data;
3094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3096 /* If canceled by the user, ignore the error given by Tinymail */
3098 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3100 /* If the operation was a sync then the status is
3101 failed, but if it's part of another operation then
3102 just set it as finished with errors */
3103 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3104 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3106 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3107 priv->error = g_error_copy ((const GError *) err);
3108 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3110 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3113 modest_mail_operation_notify_end (mail_op);
3114 g_object_unref (mail_op);
3118 modest_mail_operation_sync_folder (ModestMailOperation *self,
3119 TnyFolder *folder, gboolean expunge)
3121 ModestMailOperationPrivate *priv;
3123 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3124 g_return_if_fail (TNY_IS_FOLDER (folder));
3125 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3127 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3128 priv->account = modest_tny_folder_get_account (folder);
3129 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3131 modest_mail_operation_notify_start (self);
3132 g_object_ref (self);
3133 tny_folder_sync_async (folder, expunge,
3134 (TnyFolderCallback) sync_folder_finish_callback,
3139 modest_mail_operation_notify_start (ModestMailOperation *self)
3141 ModestMailOperationPrivate *priv = NULL;
3143 g_return_if_fail (self);
3145 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3147 /* Ensure that all the fields are filled correctly */
3148 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3150 /* Notify the observers about the mail operation. We do not
3151 wrapp this emission because we assume that this function is
3152 always called from within the main lock */
3153 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3158 * It's used by the mail operation queue to notify the observers
3159 * attached to that signal that the operation finished. We need to use
3160 * that because tinymail does not give us the progress of a given
3161 * operation when it finishes (it directly calls the operation
3165 modest_mail_operation_notify_end (ModestMailOperation *self)
3167 ModestMailOperationPrivate *priv = NULL;
3169 g_return_if_fail (self);
3171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3173 /* Notify the observers about the mail operation end. We do
3174 not wrapp this emission because we assume that this
3175 function is always called from within the main lock */
3176 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3178 /* Remove the error user data */
3179 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3180 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3184 modest_mail_operation_get_account (ModestMailOperation *self)
3186 ModestMailOperationPrivate *priv = NULL;
3188 g_return_val_if_fail (self, NULL);
3190 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3192 return (priv->account) ? g_object_ref (priv->account) : NULL;
3196 modest_mail_operation_noop (ModestMailOperation *self)
3198 ModestMailOperationPrivate *priv = NULL;
3200 g_return_if_fail (self);
3202 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3203 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3204 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3208 /* This mail operation does nothing actually */
3209 modest_mail_operation_notify_start (self);
3210 modest_mail_operation_notify_end (self);
3215 modest_mail_operation_to_string (ModestMailOperation *self)
3217 const gchar *type, *status, *account_id;
3218 ModestMailOperationPrivate *priv = NULL;
3220 g_return_val_if_fail (self, NULL);
3222 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3224 /* new operations don't have anything interesting */
3225 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3226 return g_strdup_printf ("%p <new operation>", self);
3228 switch (priv->op_type) {
3229 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3230 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3231 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3232 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3233 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3234 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3235 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3236 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3237 default: type = "UNEXPECTED"; break;
3240 switch (priv->status) {
3241 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3242 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3243 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3244 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3245 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3246 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3247 default: status= "UNEXPECTED"; break;
3250 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3252 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3253 priv->done, priv->total,
3254 priv->error && priv->error->message ? priv->error->message : "");