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-error.h>
45 #include <tny-folder-observer.h>
46 #include <camel/camel-stream-mem.h>
47 #include <glib/gi18n.h>
48 #include <modest-defs.h>
49 #include "modest-platform.h"
50 #include "modest-account-mgr-helpers.h"
51 #include <modest-tny-account.h>
52 #include <modest-tny-send-queue.h>
53 #include <modest-runtime.h>
54 #include "modest-text-utils.h"
55 #include "modest-tny-msg.h"
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account-store.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-marshal.h"
60 #include "modest-error.h"
61 #include "modest-mail-operation.h"
62 #include <modest-count-stream.h>
63 #include <libgnomevfs/gnome-vfs.h>
64 #include "modest-utils.h"
65 #include "modest-debug.h"
70 * Remove all these #ifdef stuff when the tinymail's idle calls become
73 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
75 /* 'private'/'protected' functions */
76 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
77 static void modest_mail_operation_init (ModestMailOperation *obj);
78 static void modest_mail_operation_finalize (GObject *obj);
80 static void get_msg_async_cb (TnyFolder *folder,
86 static void get_msg_status_cb (GObject *obj,
90 static void modest_mail_operation_notify_start (ModestMailOperation *self);
91 static void modest_mail_operation_notify_end (ModestMailOperation *self);
93 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
95 gint *last_total_bytes,
96 gint *sum_total_bytes,
98 gboolean increment_done);
100 static guint compute_message_list_size (TnyList *headers, guint num_elements);
102 static int compare_headers_by_date (gconstpointer a,
105 static void sync_folder_finish_callback (TnyFolder *self,
110 static gboolean _check_memory_low (ModestMailOperation *mail_op);
114 ModestTnySendQueue *queue;
115 ModestMailOperation *self;
121 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
122 ModestMailOperationStatus status);
124 /* Helpers for the update account operation (send & receive)*/
127 ModestMailOperation *mail_op;
129 UpdateAccountCallback callback;
134 TnyFolderObserver *inbox_observer;
135 RetrieveAllCallback retrieve_all_cb;
136 gboolean interactive;
140 static void destroy_update_account_info (UpdateAccountInfo *info);
142 static void update_account_send_mail (UpdateAccountInfo *info);
144 static void update_account_get_msg_async_cb (TnyFolder *folder,
150 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
151 TnyList *new_headers);
153 enum _ModestMailOperationSignals
155 PROGRESS_CHANGED_SIGNAL,
156 OPERATION_STARTED_SIGNAL,
157 OPERATION_FINISHED_SIGNAL,
161 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
162 struct _ModestMailOperationPrivate {
168 ErrorCheckingUserCallback error_checking;
169 gpointer error_checking_user_data;
170 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
171 ModestMailOperationStatus status;
172 ModestMailOperationTypeOperation op_type;
175 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
176 MODEST_TYPE_MAIL_OPERATION, \
177 ModestMailOperationPrivate))
179 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
180 priv->status = new_status;\
185 GetMsgAsyncUserCallback user_callback;
187 TnyIterator *more_msgs;
189 ModestMailOperation *mail_op;
190 GDestroyNotify destroy_notify;
191 gint last_total_bytes;
192 gint sum_total_bytes;
196 typedef struct _RefreshAsyncHelper {
197 ModestMailOperation *mail_op;
198 RefreshAsyncUserCallback user_callback;
200 } RefreshAsyncHelper;
202 typedef struct _XFerMsgsAsyncHelper
204 ModestMailOperation *mail_op;
206 TnyIterator *more_msgs;
207 TnyFolder *dest_folder;
208 XferMsgsAsyncUserCallback user_callback;
211 gint last_total_bytes;
212 gint sum_total_bytes;
214 } XFerMsgsAsyncHelper;
216 typedef struct _XFerFolderAsyncHelper
218 ModestMailOperation *mail_op;
219 XferFolderAsyncUserCallback user_callback;
221 } XFerFolderAsyncHelper;
223 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
227 static void modest_mail_operation_create_msg (ModestMailOperation *self,
228 const gchar *from, const gchar *to,
229 const gchar *cc, const gchar *bcc,
230 const gchar *subject, const gchar *plain_body,
231 const gchar *html_body, const GList *attachments_list,
232 const GList *images_list,
233 TnyHeaderFlags priority_flags,
234 const gchar *references, const gchar *in_reply_to,
235 ModestMailOperationCreateMsgCallback callback,
238 static gboolean idle_notify_queue (gpointer data);
241 ModestMailOperation *mail_op;
251 GList *attachments_list;
253 TnyHeaderFlags priority_flags;
254 ModestMailOperationCreateMsgCallback callback;
260 ModestMailOperation *mail_op;
262 ModestMailOperationCreateMsgCallback callback;
267 static GObjectClass *parent_class = NULL;
269 static guint signals[NUM_SIGNALS] = {0};
272 modest_mail_operation_get_type (void)
274 static GType my_type = 0;
276 static const GTypeInfo my_info = {
277 sizeof(ModestMailOperationClass),
278 NULL, /* base init */
279 NULL, /* base finalize */
280 (GClassInitFunc) modest_mail_operation_class_init,
281 NULL, /* class finalize */
282 NULL, /* class data */
283 sizeof(ModestMailOperation),
285 (GInstanceInitFunc) modest_mail_operation_init,
288 my_type = g_type_register_static (G_TYPE_OBJECT,
289 "ModestMailOperation",
296 modest_mail_operation_class_init (ModestMailOperationClass *klass)
298 GObjectClass *gobject_class;
299 gobject_class = (GObjectClass*) klass;
301 parent_class = g_type_class_peek_parent (klass);
302 gobject_class->finalize = modest_mail_operation_finalize;
304 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
307 * ModestMailOperation::progress-changed
308 * @self: the #MailOperation that emits the signal
309 * @user_data: user data set when the signal handler was connected
311 * Emitted when the progress of a mail operation changes
313 signals[PROGRESS_CHANGED_SIGNAL] =
314 g_signal_new ("progress-changed",
315 G_TYPE_FROM_CLASS (gobject_class),
317 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
319 g_cclosure_marshal_VOID__POINTER,
320 G_TYPE_NONE, 1, G_TYPE_POINTER);
324 * This signal is issued whenever a mail operation starts, and
325 * starts mean when the tinymail operation is issued. This
326 * means that it could happen that something wrong happens and
327 * the tinymail function is never called. In this situation a
328 * operation-finished will be issued without any
331 signals[OPERATION_STARTED_SIGNAL] =
332 g_signal_new ("operation-started",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
337 g_cclosure_marshal_VOID__VOID,
342 * This signal is issued whenever a mail operation
343 * finishes. Note that this signal could be issued without any
344 * previous "operation-started" signal, because this last one
345 * is only issued when the tinymail operation is successfully
348 signals[OPERATION_FINISHED_SIGNAL] =
349 g_signal_new ("operation-finished",
350 G_TYPE_FROM_CLASS (gobject_class),
352 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
354 g_cclosure_marshal_VOID__VOID,
359 modest_mail_operation_init (ModestMailOperation *obj)
361 ModestMailOperationPrivate *priv;
363 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
365 priv->account = NULL;
366 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
367 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
372 priv->error_checking = NULL;
373 priv->error_checking_user_data = NULL;
377 modest_mail_operation_finalize (GObject *obj)
379 ModestMailOperationPrivate *priv;
381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
386 g_error_free (priv->error);
390 g_object_unref (priv->source);
394 g_object_unref (priv->account);
395 priv->account = NULL;
399 G_OBJECT_CLASS(parent_class)->finalize (obj);
403 modest_mail_operation_new (GObject *source)
405 ModestMailOperation *obj;
406 ModestMailOperationPrivate *priv;
408 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
412 priv->source = g_object_ref(source);
418 modest_mail_operation_new_with_error_handling (GObject *source,
419 ErrorCheckingUserCallback error_handler,
421 ErrorCheckingUserDataDestroyer error_handler_destroyer)
423 ModestMailOperation *obj;
424 ModestMailOperationPrivate *priv;
426 obj = modest_mail_operation_new (source);
427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
429 g_return_val_if_fail (error_handler != NULL, obj);
430 priv->error_checking = error_handler;
431 priv->error_checking_user_data = user_data;
432 priv->error_checking_user_data_destroyer = error_handler_destroyer;
438 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
445 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
447 /* Call the user callback */
448 if (priv->error_checking != NULL)
449 priv->error_checking (self, priv->error_checking_user_data);
453 ModestMailOperationTypeOperation
454 modest_mail_operation_get_type_operation (ModestMailOperation *self)
456 ModestMailOperationPrivate *priv;
458 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
459 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
461 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
463 return priv->op_type;
467 modest_mail_operation_is_mine (ModestMailOperation *self,
470 ModestMailOperationPrivate *priv;
472 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
475 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
476 if (priv->source == NULL) return FALSE;
478 return priv->source == me;
482 modest_mail_operation_get_source (ModestMailOperation *self)
484 ModestMailOperationPrivate *priv;
486 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
491 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
495 return (priv->source) ? g_object_ref (priv->source) : NULL;
498 ModestMailOperationStatus
499 modest_mail_operation_get_status (ModestMailOperation *self)
501 ModestMailOperationPrivate *priv;
503 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
504 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
505 MODEST_MAIL_OPERATION_STATUS_INVALID);
507 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
509 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
510 return MODEST_MAIL_OPERATION_STATUS_INVALID;
517 modest_mail_operation_get_error (ModestMailOperation *self)
519 ModestMailOperationPrivate *priv;
521 g_return_val_if_fail (self, NULL);
522 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
527 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
535 modest_mail_operation_cancel (ModestMailOperation *self)
537 ModestMailOperationPrivate *priv;
538 gboolean canceled = FALSE;
540 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
542 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
547 /* Cancel the mail operation */
548 g_return_val_if_fail (priv->account, FALSE);
549 tny_account_cancel (priv->account);
551 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
552 ModestTnySendQueue *queue;
553 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
556 /* Cancel the sending of the following next messages */
557 if (TNY_IS_SEND_QUEUE (queue))
558 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
565 modest_mail_operation_get_task_done (ModestMailOperation *self)
567 ModestMailOperationPrivate *priv;
569 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
572 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
577 modest_mail_operation_get_task_total (ModestMailOperation *self)
579 ModestMailOperationPrivate *priv;
581 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
589 modest_mail_operation_is_finished (ModestMailOperation *self)
591 ModestMailOperationPrivate *priv;
592 gboolean retval = FALSE;
594 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
599 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
600 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
601 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
602 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
612 * Creates an image of the current state of a mail operation, the
613 * caller must free it
615 static ModestMailOperationState *
616 modest_mail_operation_clone_state (ModestMailOperation *self)
618 ModestMailOperationState *state;
619 ModestMailOperationPrivate *priv;
621 g_return_val_if_fail (self, NULL);
622 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
623 g_return_val_if_fail (priv, NULL);
628 state = g_slice_new (ModestMailOperationState);
630 state->status = priv->status;
631 state->op_type = priv->op_type;
632 state->done = priv->done;
633 state->total = priv->total;
634 state->finished = modest_mail_operation_is_finished (self);
635 state->bytes_done = 0;
636 state->bytes_total = 0;
641 /* ******************************************************************* */
642 /* ************************** SEND ACTIONS ************************* */
643 /* ******************************************************************* */
647 ModestMailOperation *mail_op;
652 send_mail_on_sync_async_cb (TnyFolder *folder,
657 ModestMailOperationPrivate *priv;
658 ModestMailOperation *self;
659 SendNewMailHelper *helper;
661 helper = (SendNewMailHelper *) user_data;
662 self = helper->mail_op;
663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
665 if (cancelled || err)
669 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
670 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
671 "Error adding a msg to the send queue\n");
672 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
674 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
679 modest_mail_operation_notify_end (self);
681 g_object_unref (helper->mail_op);
682 g_slice_free (SendNewMailHelper, helper);
686 run_queue_start (TnySendQueue *self,
689 RunQueueHelper *helper = (RunQueueHelper *) user_data;
690 ModestMailOperation *mail_op;
692 g_debug ("%s sending queue successfully started", __FUNCTION__);
694 /* Wait for the message to be sent */
695 mail_op = modest_mail_operation_new (NULL);
696 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
698 modest_mail_operation_run_queue (mail_op, helper->queue);
699 g_object_unref (mail_op);
701 /* Free the helper and end operation */
702 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
706 run_queue_error_happened (TnySendQueue *queue,
712 RunQueueHelper *helper = (RunQueueHelper *) user_data;
713 ModestMailOperationPrivate *priv;
715 /* If we are here this means that the send queue could not
716 start to send emails. Shouldn't happen as this means that
717 we could not create the thread */
718 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
720 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
721 priv->error = g_error_copy ((const GError *) error);
723 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
724 /* This code is here for safety reasons. It should
725 never be called, because that would mean that we
726 are not controlling some error case */
727 g_warning ("%s Error %s should not happen",
728 __FUNCTION__, error->message);
731 /* Free helper and end operation */
732 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
736 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
742 ModestMailOperationPrivate *priv;
743 ModestMailOperation *self;
744 SendNewMailHelper *helper;
746 helper = (SendNewMailHelper *) user_data;
747 self = helper->mail_op;
748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
750 if (cancelled || err)
754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
755 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
756 "Error adding a msg to the send queue\n");
757 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
759 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
763 if (helper->notify) {
764 TnyTransportAccount *trans_account;
765 ModestTnySendQueue *queue;
767 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
768 queue = modest_runtime_get_send_queue (trans_account, TRUE);
770 RunQueueHelper *helper;
772 /* Create the helper */
773 helper = g_slice_new0 (RunQueueHelper);
774 helper->queue = g_object_ref (queue);
775 helper->self = g_object_ref (self);
777 /* if sending is ongoing wait for the queue to
778 stop. Otherwise wait for the queue-start
779 signal. It could happen that the queue
780 could not start, then check also the error
782 if (modest_tny_send_queue_sending_in_progress (queue)) {
783 run_queue_start (TNY_SEND_QUEUE (queue), helper);
785 helper->start_handler = g_signal_connect (queue, "queue-start",
786 G_CALLBACK (run_queue_start),
788 helper->error_handler = g_signal_connect (queue, "error-happened",
789 G_CALLBACK (run_queue_error_happened),
793 /* Finalize this mail operation */
794 modest_mail_operation_notify_end (self);
796 g_object_unref (trans_account);
799 g_object_unref (helper->mail_op);
800 g_slice_free (SendNewMailHelper, helper);
804 idle_create_msg_cb (gpointer idle_data)
806 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
808 /* This is a GDK lock because we are an idle callback and
809 * info->callback can contain Gtk+ code */
811 gdk_threads_enter (); /* CHECKED */
812 info->callback (info->mail_op, info->msg, info->userdata);
814 g_object_unref (info->mail_op);
816 g_object_unref (info->msg);
817 g_slice_free (CreateMsgIdleInfo, info);
818 gdk_threads_leave (); /* CHECKED */
824 create_msg_thread (gpointer thread_data)
826 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
827 TnyMsg *new_msg = NULL;
828 ModestMailOperationPrivate *priv;
831 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
832 if (info->html_body == NULL) {
833 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
834 info->bcc, info->subject,
835 info->references, info->in_reply_to,
837 info->attachments_list, &attached,
840 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
841 info->bcc, info->subject,
842 info->references, info->in_reply_to,
844 info->plain_body, info->attachments_list,
845 info->images_list, &attached,
852 /* Set priority flags in message */
853 header = tny_msg_get_header (new_msg);
854 tny_header_set_flag (header, info->priority_flags);
856 /* Set attachment flags in message */
857 if (info->attachments_list != NULL && attached > 0)
858 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
860 g_object_unref (G_OBJECT(header));
862 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
864 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
865 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
866 "modest: failed to create a new msg\n");
874 g_free (info->plain_body);
875 g_free (info->html_body);
876 g_free (info->subject);
877 g_free (info->references);
878 g_free (info->in_reply_to);
879 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
880 g_list_free (info->attachments_list);
881 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
882 g_list_free (info->images_list);
884 if (info->callback) {
885 CreateMsgIdleInfo *idle_info;
886 idle_info = g_slice_new0 (CreateMsgIdleInfo);
887 idle_info->mail_op = g_object_ref (info->mail_op);
888 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
889 idle_info->callback = info->callback;
890 idle_info->userdata = info->userdata;
891 g_idle_add (idle_create_msg_cb, idle_info);
893 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
896 g_object_unref (info->mail_op);
897 g_slice_free (CreateMsgInfo, info);
898 if (new_msg) g_object_unref(new_msg);
904 modest_mail_operation_create_msg (ModestMailOperation *self,
905 const gchar *from, const gchar *to,
906 const gchar *cc, const gchar *bcc,
907 const gchar *subject, const gchar *plain_body,
908 const gchar *html_body,
909 const GList *attachments_list,
910 const GList *images_list,
911 TnyHeaderFlags priority_flags,
912 const gchar *references,
913 const gchar *in_reply_to,
914 ModestMailOperationCreateMsgCallback callback,
917 CreateMsgInfo *info = NULL;
919 info = g_slice_new0 (CreateMsgInfo);
920 info->mail_op = g_object_ref (self);
922 info->from = g_strdup (from);
923 info->to = g_strdup (to);
924 info->cc = g_strdup (cc);
925 info->bcc = g_strdup (bcc);
926 info->subject = g_strdup (subject);
927 info->plain_body = g_strdup (plain_body);
928 info->html_body = g_strdup (html_body);
929 info->references = g_strdup (references);
930 info->in_reply_to = g_strdup (in_reply_to);
931 info->attachments_list = g_list_copy ((GList *) attachments_list);
932 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
933 info->images_list = g_list_copy ((GList *) images_list);
934 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
935 info->priority_flags = priority_flags;
937 info->callback = callback;
938 info->userdata = userdata;
940 g_thread_create (create_msg_thread, info, FALSE, NULL);
945 TnyTransportAccount *transport_account;
950 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
954 TnySendQueue *send_queue = NULL;
955 ModestMailOperationPrivate *priv = NULL;
956 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
957 TnyFolder *draft_folder = NULL;
958 TnyFolder *outbox_folder = NULL;
959 TnyHeader *header = NULL;
961 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
964 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
965 modest_mail_operation_notify_end (self);
969 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
970 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
971 modest_mail_operation_notify_end (self);
975 /* Add message to send queue */
976 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
977 if (!TNY_IS_SEND_QUEUE(send_queue)) {
979 g_error_free (priv->error);
982 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
983 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
984 "modest: could not find send queue for account\n");
985 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
986 modest_mail_operation_notify_end (self);
989 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
990 helper->mail_op = g_object_ref (self);
991 helper->notify = (info->draft_msg == NULL);
993 /* Add the msg to the queue. The callback will free
995 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
997 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1001 if (info->draft_msg != NULL) {
1002 TnyList *tmp_headers = NULL;
1003 TnyFolder *folder = NULL;
1004 TnyFolder *src_folder = NULL;
1005 TnyFolderType folder_type;
1006 TnyTransportAccount *transport_account = NULL;
1007 SendNewMailHelper *helper = NULL;
1009 /* To remove the old mail from its source folder, we need to get the
1010 * transport account of the original draft message (the transport account
1011 * might have been changed by the user) */
1012 header = tny_msg_get_header (info->draft_msg);
1013 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1014 modest_runtime_get_account_store(), header);
1015 if (transport_account == NULL)
1016 transport_account = g_object_ref(info->transport_account);
1017 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1018 TNY_FOLDER_TYPE_DRAFTS);
1019 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1020 TNY_FOLDER_TYPE_OUTBOX);
1021 g_object_unref(transport_account);
1023 if (!draft_folder) {
1024 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1026 modest_mail_operation_notify_end (self);
1029 if (!outbox_folder) {
1030 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1032 modest_mail_operation_notify_end (self);
1036 folder = tny_msg_get_folder (info->draft_msg);
1037 if (folder == NULL) {
1038 modest_mail_operation_notify_end (self);
1041 folder_type = modest_tny_folder_guess_folder_type (folder);
1043 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1044 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1046 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1047 src_folder = outbox_folder;
1049 src_folder = draft_folder;
1051 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1052 * because this function requires it to have a UID. */
1053 helper = g_slice_new (SendNewMailHelper);
1054 helper->mail_op = g_object_ref (self);
1055 helper->notify = TRUE;
1057 tmp_headers = tny_simple_list_new ();
1058 tny_list_append (tmp_headers, (GObject*) header);
1059 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1060 g_object_unref (tmp_headers);
1061 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1063 g_object_unref (folder);
1068 g_object_unref (header);
1069 if (info->draft_msg)
1070 g_object_unref (info->draft_msg);
1072 g_object_unref (draft_folder);
1074 g_object_unref (outbox_folder);
1075 if (info->transport_account)
1076 g_object_unref (info->transport_account);
1077 g_slice_free (SendNewMailInfo, info);
1081 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1082 TnyTransportAccount *transport_account,
1084 const gchar *from, const gchar *to,
1085 const gchar *cc, const gchar *bcc,
1086 const gchar *subject, const gchar *plain_body,
1087 const gchar *html_body,
1088 const GList *attachments_list,
1089 const GList *images_list,
1090 const gchar *references,
1091 const gchar *in_reply_to,
1092 TnyHeaderFlags priority_flags)
1094 ModestMailOperationPrivate *priv = NULL;
1095 SendNewMailInfo *info;
1097 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1098 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1101 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1102 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1103 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1105 modest_mail_operation_notify_start (self);
1107 /* Check parametters */
1109 /* Set status failed and set an error */
1110 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1111 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1112 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1113 _("Error trying to send a mail. You need to set at least one recipient"));
1114 modest_mail_operation_notify_end (self);
1117 info = g_slice_new0 (SendNewMailInfo);
1118 info->transport_account = transport_account;
1119 if (transport_account)
1120 g_object_ref (transport_account);
1121 info->draft_msg = draft_msg;
1123 g_object_ref (draft_msg);
1126 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1127 attachments_list, images_list, priority_flags,
1128 references, in_reply_to,
1129 modest_mail_operation_send_new_mail_cb, info);
1135 TnyTransportAccount *transport_account;
1137 SaveToDraftstCallback callback;
1141 ModestMailOperation *mailop;
1142 } SaveToDraftsAddMsgInfo;
1145 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1150 ModestMailOperationPrivate *priv = NULL;
1151 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1152 GError *io_error = NULL;
1154 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1156 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1157 io_error = priv->error;
1161 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1162 g_error_free(priv->error);
1165 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1167 if ((!priv->error) && (info->draft_msg != NULL)) {
1168 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1169 TnyFolder *src_folder = tny_header_get_folder (header);
1171 g_debug ("--- REMOVE AND SYNC");
1172 /* Remove the old draft */
1173 tny_folder_remove_msg (src_folder, header, NULL);
1175 /* Synchronize to expunge and to update the msg counts */
1176 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1177 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1178 g_debug ("--- REMOVED - SYNCED");
1180 g_object_unref (G_OBJECT(header));
1181 g_object_unref (G_OBJECT(src_folder));
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1187 g_error_free (io_error);
1190 } else if (io_error) {
1191 priv->error = io_error;
1192 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1194 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1197 /* Call the user callback */
1199 info->callback (info->mailop, info->msg, info->user_data);
1201 if (info->transport_account)
1202 g_object_unref (G_OBJECT(info->transport_account));
1203 if (info->draft_msg)
1204 g_object_unref (G_OBJECT (info->draft_msg));
1206 g_object_unref (G_OBJECT(info->drafts));
1208 g_object_unref (G_OBJECT (info->msg));
1210 modest_mail_operation_notify_end (info->mailop);
1211 g_object_unref(info->mailop);
1212 g_slice_free (SaveToDraftsAddMsgInfo, info);
1217 TnyTransportAccount *transport_account;
1219 SaveToDraftstCallback callback;
1224 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1228 TnyFolder *drafts = NULL;
1229 ModestMailOperationPrivate *priv = NULL;
1230 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1232 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1235 if (!(priv->error)) {
1236 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1237 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1238 "modest: failed to create a new msg\n");
1241 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1242 TNY_FOLDER_TYPE_DRAFTS);
1243 if (!drafts && !(priv->error)) {
1244 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1245 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1246 "modest: failed to create a new msg\n");
1250 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1252 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1253 cb_info->transport_account = g_object_ref(info->transport_account);
1254 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1255 cb_info->callback = info->callback;
1256 cb_info->user_data = info->user_data;
1257 cb_info->drafts = g_object_ref(drafts);
1258 cb_info->msg = g_object_ref(msg);
1259 cb_info->mailop = g_object_ref(self);
1260 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1264 /* Call the user callback */
1265 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1267 info->callback (self, msg, info->user_data);
1268 modest_mail_operation_notify_end (self);
1272 g_object_unref (G_OBJECT(drafts));
1273 if (info->draft_msg)
1274 g_object_unref (G_OBJECT (info->draft_msg));
1275 if (info->transport_account)
1276 g_object_unref (G_OBJECT(info->transport_account));
1277 g_slice_free (SaveToDraftsInfo, info);
1281 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1282 TnyTransportAccount *transport_account,
1284 const gchar *from, const gchar *to,
1285 const gchar *cc, const gchar *bcc,
1286 const gchar *subject, const gchar *plain_body,
1287 const gchar *html_body,
1288 const GList *attachments_list,
1289 const GList *images_list,
1290 TnyHeaderFlags priority_flags,
1291 const gchar *references,
1292 const gchar *in_reply_to,
1293 SaveToDraftstCallback callback,
1296 ModestMailOperationPrivate *priv = NULL;
1297 SaveToDraftsInfo *info = NULL;
1299 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1300 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1302 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1304 /* Get account and set it into mail_operation */
1305 priv->account = g_object_ref (transport_account);
1306 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1308 info = g_slice_new0 (SaveToDraftsInfo);
1309 info->transport_account = g_object_ref (transport_account);
1310 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1311 info->callback = callback;
1312 info->user_data = user_data;
1314 g_debug ("--- CREATE MESSAGE");
1315 modest_mail_operation_notify_start (self);
1316 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1317 attachments_list, images_list, priority_flags,
1318 references, in_reply_to,
1319 modest_mail_operation_save_to_drafts_cb, info);
1324 ModestMailOperation *mail_op;
1325 TnyMimePart *mime_part;
1327 GetMimePartSizeCallback callback;
1329 } GetMimePartSizeInfo;
1331 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1332 /* We use this folder observer to track the headers that have been
1333 * added to a folder */
1336 TnyList *new_headers;
1337 } InternalFolderObserver;
1340 GObjectClass parent;
1341 } InternalFolderObserverClass;
1343 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1345 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1346 internal_folder_observer,
1348 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1352 foreach_add_item (gpointer header, gpointer user_data)
1354 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1357 /* This is the method that looks for new messages in a folder */
1359 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1361 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1363 TnyFolderChangeChanged changed;
1365 changed = tny_folder_change_get_changed (change);
1367 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1370 /* Get added headers */
1371 list = tny_simple_list_new ();
1372 tny_folder_change_get_added_headers (change, list);
1374 /* Add them to the folder observer */
1375 tny_list_foreach (list, foreach_add_item,
1376 derived->new_headers);
1378 g_object_unref (G_OBJECT (list));
1383 internal_folder_observer_init (InternalFolderObserver *self)
1385 self->new_headers = tny_simple_list_new ();
1388 internal_folder_observer_finalize (GObject *object)
1390 InternalFolderObserver *self;
1392 self = (InternalFolderObserver *) object;
1393 g_object_unref (self->new_headers);
1395 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1398 tny_folder_observer_init (TnyFolderObserverIface *iface)
1400 iface->update = internal_folder_observer_update;
1403 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1405 GObjectClass *object_class;
1407 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1408 object_class = (GObjectClass*) klass;
1409 object_class->finalize = internal_folder_observer_finalize;
1413 destroy_update_account_info (UpdateAccountInfo *info)
1415 g_free (info->account_name);
1416 g_object_unref (info->folders);
1417 g_object_unref (info->mail_op);
1418 g_slice_free (UpdateAccountInfo, info);
1423 update_account_send_mail (UpdateAccountInfo *info)
1425 TnyTransportAccount *transport_account = NULL;
1426 ModestTnyAccountStore *account_store;
1428 account_store = modest_runtime_get_account_store ();
1430 /* We don't try to send messages while sending mails is blocked */
1431 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1434 /* Get the transport account */
1435 transport_account = (TnyTransportAccount *)
1436 modest_tny_account_store_get_server_account (account_store, info->account_name,
1437 TNY_ACCOUNT_TYPE_TRANSPORT);
1439 if (transport_account) {
1440 ModestTnySendQueue *send_queue;
1444 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1445 g_object_unref (transport_account);
1447 if (TNY_IS_SEND_QUEUE (send_queue)) {
1448 /* Get outbox folder */
1449 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1450 if (outbox) { /* this could fail in some cases */
1451 num_messages = tny_folder_get_all_count (outbox);
1452 g_object_unref (outbox);
1454 g_warning ("%s: could not get outbox", __FUNCTION__);
1458 if (num_messages != 0) {
1459 ModestMailOperation *mail_op;
1460 /* Reenable suspended items */
1461 mail_op = modest_mail_operation_new (NULL);
1462 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1464 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1467 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1475 update_account_get_msg_async_cb (TnyFolder *folder,
1481 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1482 ModestMailOperationPrivate *priv;
1484 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1487 if (TNY_IS_MSG (msg)) {
1488 TnyHeader *header = tny_msg_get_header (msg);
1491 ModestMailOperationState *state;
1492 state = modest_mail_operation_clone_state (msg_info->mail_op);
1493 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1494 state->bytes_done = msg_info->sum_total_bytes;
1495 state->bytes_total = msg_info->total_bytes;
1497 /* Notify the status change. Only notify about changes
1498 referred to bytes */
1499 g_signal_emit (G_OBJECT (msg_info->mail_op),
1500 signals[PROGRESS_CHANGED_SIGNAL],
1503 g_object_unref (header);
1504 g_slice_free (ModestMailOperationState, state);
1508 if (priv->done == priv->total) {
1509 TnyList *new_headers;
1510 UpdateAccountInfo *info;
1512 /* After getting all the messages send the ones in the
1514 info = (UpdateAccountInfo *) msg_info->user_data;
1515 update_account_send_mail (info);
1517 /* Check if the operation was a success */
1519 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1521 /* Call the user callback and free */
1522 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1523 update_account_notify_user_and_free (info, new_headers);
1524 g_object_unref (new_headers);
1526 /* Delete the helper */
1527 g_object_unref (msg_info->more_msgs);
1528 g_object_unref (msg_info->mail_op);
1529 g_slice_free (GetMsgInfo, msg_info);
1534 update_account_notify_user_and_free (UpdateAccountInfo *info,
1535 TnyList *new_headers)
1537 /* Set the account back to not busy */
1538 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1539 info->account_name, FALSE);
1543 info->callback (info->mail_op, new_headers, info->user_data);
1545 /* Mail operation end */
1546 modest_mail_operation_notify_end (info->mail_op);
1550 g_object_unref (new_headers);
1551 destroy_update_account_info (info);
1555 inbox_refreshed_cb (TnyFolder *inbox,
1560 UpdateAccountInfo *info;
1561 ModestMailOperationPrivate *priv;
1562 TnyIterator *new_headers_iter;
1563 GPtrArray *new_headers_array = NULL;
1564 gint max_size, retrieve_limit, i;
1565 ModestAccountMgr *mgr;
1566 ModestAccountRetrieveType retrieve_type;
1567 TnyList *new_headers = NULL;
1568 gboolean headers_only, ignore_limit;
1570 info = (UpdateAccountInfo *) user_data;
1571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1572 mgr = modest_runtime_get_account_mgr ();
1574 if (canceled || err) {
1575 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1577 priv->error = g_error_copy (err);
1579 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1580 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1584 tny_folder_remove_observer (inbox, info->inbox_observer);
1585 g_object_unref (info->inbox_observer);
1586 info->inbox_observer = NULL;
1588 /* Notify the user about the error and then exit */
1589 update_account_notify_user_and_free (info, NULL);
1594 /* Try to send anyway */
1598 /* Set the last updated as the current time */
1599 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1601 /* Get the message max size */
1602 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1603 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1605 max_size = G_MAXINT;
1607 max_size = max_size * KB;
1609 /* Create the new headers array. We need it to sort the
1610 new headers by date */
1611 new_headers_array = g_ptr_array_new ();
1612 if (info->inbox_observer) {
1613 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1614 while (!tny_iterator_is_done (new_headers_iter)) {
1615 TnyHeader *header = NULL;
1617 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1618 /* Apply per-message size limits */
1619 if (tny_header_get_message_size (header) < max_size)
1620 g_ptr_array_add (new_headers_array, g_object_ref (header));
1622 g_object_unref (header);
1623 tny_iterator_next (new_headers_iter);
1625 g_object_unref (new_headers_iter);
1627 tny_folder_remove_observer (inbox, info->inbox_observer);
1628 g_object_unref (info->inbox_observer);
1629 info->inbox_observer = NULL;
1632 if (new_headers_array->len == 0) {
1633 g_ptr_array_free (new_headers_array, FALSE);
1637 /* Get per-account message amount retrieval limit */
1638 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1639 if (retrieve_limit == 0)
1640 retrieve_limit = G_MAXINT;
1642 /* Get per-account retrieval type */
1643 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1644 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1647 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1649 /* Ask the users if they want to retrieve all the messages
1650 even though the limit was exceeded */
1651 ignore_limit = FALSE;
1652 if (new_headers_array->len > retrieve_limit) {
1653 /* Ask the user if a callback has been specified and
1654 if the mail operation has a source (this means that
1655 was invoked by the user and not automatically by a
1657 if (info->retrieve_all_cb && priv->source)
1658 ignore_limit = info->retrieve_all_cb (priv->source,
1659 new_headers_array->len,
1663 /* Copy the headers to a list and free the array */
1664 new_headers = tny_simple_list_new ();
1665 for (i=0; i < new_headers_array->len; i++) {
1666 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1667 tny_list_append (new_headers, G_OBJECT (header));
1669 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1670 g_ptr_array_free (new_headers_array, FALSE);
1672 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1675 GetMsgInfo *msg_info;
1679 priv->total = tny_list_get_length (new_headers);
1681 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1683 iter = tny_list_create_iterator (new_headers);
1685 /* Create the message info */
1686 msg_info = g_slice_new0 (GetMsgInfo);
1687 msg_info->mail_op = g_object_ref (info->mail_op);
1688 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1689 msg_info->more_msgs = g_object_ref (iter);
1690 msg_info->user_data = info;
1692 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1693 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1694 TnyFolder *folder = tny_header_get_folder (header);
1696 /* Get message in an async way */
1697 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1700 g_object_unref (folder);
1703 tny_iterator_next (iter);
1705 g_object_unref (iter);
1707 /* The mail operation will finish when the last
1708 message is retrieved */
1712 /* If we don't have to retrieve the new messages then
1714 update_account_send_mail (info);
1716 /* Check if the operation was a success */
1718 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1720 /* Call the user callback and free */
1721 update_account_notify_user_and_free (info, new_headers);
1725 inbox_refresh_status_update (GObject *obj,
1729 UpdateAccountInfo *info = NULL;
1730 ModestMailOperation *self = NULL;
1731 ModestMailOperationPrivate *priv = NULL;
1732 ModestMailOperationState *state;
1734 g_return_if_fail (user_data != NULL);
1735 g_return_if_fail (status != NULL);
1737 /* Show only the status information we want */
1738 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1741 info = (UpdateAccountInfo *) user_data;
1742 self = info->mail_op;
1743 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1745 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1747 priv->done = status->position;
1748 priv->total = status->of_total;
1750 state = modest_mail_operation_clone_state (self);
1752 /* This is not a GDK lock because we are a Tinymail callback and
1753 * Tinymail already acquires the Gdk lock */
1754 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1756 g_slice_free (ModestMailOperationState, state);
1760 recurse_folders_async_cb (TnyFolderStore *folder_store,
1766 UpdateAccountInfo *info;
1767 ModestMailOperationPrivate *priv;
1769 info = (UpdateAccountInfo *) user_data;
1770 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1772 if (err || canceled) {
1773 /* If the error was previosly set by another callback
1774 don't set it again */
1776 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1778 priv->error = g_error_copy (err);
1780 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1781 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1785 /* We're not getting INBOX children if we don't want to poke all */
1786 TnyIterator *iter = tny_list_create_iterator (list);
1787 while (!tny_iterator_is_done (iter)) {
1788 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1790 /* Add to the list of all folders */
1791 tny_list_append (info->folders, (GObject *) folder);
1793 if (info->poke_all) {
1794 TnyList *folders = tny_simple_list_new ();
1795 /* Add pending call */
1796 info->pending_calls++;
1798 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1799 recurse_folders_async_cb,
1801 g_object_unref (folders);
1804 g_object_unref (G_OBJECT (folder));
1806 tny_iterator_next (iter);
1808 g_object_unref (G_OBJECT (iter));
1811 /* Remove my own pending call */
1812 info->pending_calls--;
1814 /* This means that we have all the folders */
1815 if (info->pending_calls == 0) {
1816 TnyIterator *iter_all_folders;
1817 TnyFolder *inbox = NULL;
1819 /* If there was any error do not continue */
1821 update_account_notify_user_and_free (info, NULL);
1825 iter_all_folders = tny_list_create_iterator (info->folders);
1827 /* Do a poke status over all folders */
1828 while (!tny_iterator_is_done (iter_all_folders) &&
1829 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1830 TnyFolder *folder = NULL;
1832 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1834 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1835 /* Get a reference to the INBOX */
1836 inbox = g_object_ref (folder);
1838 /* Issue a poke status over the folder */
1840 tny_folder_poke_status (folder);
1843 /* Free and go to next */
1844 g_object_unref (folder);
1845 tny_iterator_next (iter_all_folders);
1847 g_object_unref (iter_all_folders);
1849 /* Refresh the INBOX */
1851 /* Refresh the folder. Our observer receives
1852 * the new emails during folder refreshes, so
1853 * we can use observer->new_headers
1855 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1856 tny_folder_add_observer (inbox, info->inbox_observer);
1858 /* Refresh the INBOX */
1859 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1860 g_object_unref (inbox);
1862 /* We could not perform the inbox refresh but
1863 we'll try to send mails anyway */
1864 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1870 modest_mail_operation_update_account (ModestMailOperation *self,
1871 const gchar *account_name,
1873 gboolean interactive,
1874 RetrieveAllCallback retrieve_all_cb,
1875 UpdateAccountCallback callback,
1878 UpdateAccountInfo *info = NULL;
1879 ModestMailOperationPrivate *priv = NULL;
1880 ModestTnyAccountStore *account_store = NULL;
1882 ModestMailOperationState *state;
1884 /* Init mail operation */
1885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1888 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1889 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1891 /* Get the store account */
1892 account_store = modest_runtime_get_account_store ();
1894 modest_tny_account_store_get_server_account (account_store,
1896 TNY_ACCOUNT_TYPE_STORE);
1898 /* The above function could return NULL */
1899 if (!priv->account) {
1900 /* Check if the operation was a success */
1901 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1902 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1904 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1906 /* Call the user callback */
1908 callback (self, NULL, user_data);
1910 /* Notify about operation end */
1911 modest_mail_operation_notify_end (self);
1916 /* We have once seen priv->account getting finalized during this code,
1917 * therefore adding a reference (bug #82296) */
1919 g_object_ref (priv->account);
1921 /* Create the helper object */
1922 info = g_slice_new0 (UpdateAccountInfo);
1923 info->pending_calls = 1;
1924 info->folders = tny_simple_list_new ();
1925 info->mail_op = g_object_ref (self);
1926 info->poke_all = poke_all;
1927 info->interactive = interactive;
1928 info->account_name = g_strdup (account_name);
1929 info->callback = callback;
1930 info->user_data = user_data;
1931 info->retrieve_all_cb = retrieve_all_cb;
1933 /* Set account busy */
1934 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1935 modest_mail_operation_notify_start (self);
1937 /* notify about the start of the operation */
1938 state = modest_mail_operation_clone_state (self);
1942 /* Start notifying progress */
1943 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1944 g_slice_free (ModestMailOperationState, state);
1946 /* Get all folders and continue in the callback */
1947 folders = tny_simple_list_new ();
1948 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1949 folders, NULL, FALSE,
1950 recurse_folders_async_cb,
1952 g_object_unref (folders);
1954 g_object_unref (priv->account);
1959 * Used to notify the queue from the main
1960 * loop. We call it inside an idle call to achieve that
1963 idle_notify_queue (gpointer data)
1965 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1967 gdk_threads_enter ();
1968 modest_mail_operation_notify_end (mail_op);
1969 gdk_threads_leave ();
1970 g_object_unref (mail_op);
1976 compare_headers_by_date (gconstpointer a,
1979 TnyHeader **header1, **header2;
1980 time_t sent1, sent2;
1982 header1 = (TnyHeader **) a;
1983 header2 = (TnyHeader **) b;
1985 sent1 = tny_header_get_date_sent (*header1);
1986 sent2 = tny_header_get_date_sent (*header2);
1988 /* We want the most recent ones (greater time_t) at the
1997 /* ******************************************************************* */
1998 /* ************************** STORE ACTIONS ************************* */
1999 /* ******************************************************************* */
2002 ModestMailOperation *mail_op;
2003 CreateFolderUserCallback callback;
2009 create_folder_cb (TnyFolderStore *parent_folder,
2011 TnyFolder *new_folder,
2015 ModestMailOperationPrivate *priv;
2016 CreateFolderInfo *info;
2018 info = (CreateFolderInfo *) user_data;
2019 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2021 if (canceled || err) {
2022 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2024 priv->error = g_error_copy (err);
2026 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2027 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2030 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2033 /* The user will unref the new_folder */
2035 info->callback (info->mail_op, parent_folder,
2036 new_folder, info->user_data);
2038 /* Notify about operation end */
2039 modest_mail_operation_notify_end (info->mail_op);
2042 g_object_unref (info->mail_op);
2043 g_slice_free (CreateFolderInfo, info);
2047 modest_mail_operation_create_folder (ModestMailOperation *self,
2048 TnyFolderStore *parent,
2050 CreateFolderUserCallback callback,
2053 ModestMailOperationPrivate *priv;
2055 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2056 g_return_if_fail (name);
2058 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2059 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2060 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2061 g_object_ref (parent) :
2062 modest_tny_folder_get_account (TNY_FOLDER (parent));
2064 /* Check for already existing folder */
2065 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2066 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2067 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2068 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2069 _CS("ckdg_ib_folder_already_exists"));
2073 if (TNY_IS_FOLDER (parent)) {
2074 /* Check folder rules */
2075 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2076 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
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,
2081 _("mail_in_ui_folder_create_error"));
2085 if (!strcmp (name, " ") || strchr (name, '/')) {
2086 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2087 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2088 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2089 _("mail_in_ui_folder_create_error"));
2093 CreateFolderInfo *info;
2095 info = g_slice_new0 (CreateFolderInfo);
2096 info->mail_op = g_object_ref (self);
2097 info->callback = callback;
2098 info->user_data = user_data;
2100 modest_mail_operation_notify_start (self);
2102 /* Create the folder */
2103 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2106 /* Call the user callback anyway */
2108 callback (self, parent, NULL, user_data);
2109 /* Notify about operation end */
2110 modest_mail_operation_notify_end (self);
2115 modest_mail_operation_remove_folder (ModestMailOperation *self,
2117 gboolean remove_to_trash)
2119 ModestMailOperationPrivate *priv;
2120 ModestTnyFolderRules rules;
2122 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2123 g_return_if_fail (TNY_IS_FOLDER (folder));
2125 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2127 /* Check folder rules */
2128 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2129 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2130 /* Set status failed and set an error */
2131 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2132 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2133 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2134 _("mail_in_ui_folder_delete_error"));
2138 /* Get the account */
2139 priv->account = modest_tny_folder_get_account (folder);
2140 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2142 /* Delete folder or move to trash */
2143 if (remove_to_trash) {
2144 TnyFolder *trash_folder = NULL;
2145 trash_folder = modest_tny_account_get_special_folder (priv->account,
2146 TNY_FOLDER_TYPE_TRASH);
2147 /* TODO: error_handling */
2149 modest_mail_operation_notify_start (self);
2150 modest_mail_operation_xfer_folder (self, folder,
2151 TNY_FOLDER_STORE (trash_folder),
2153 g_object_unref (trash_folder);
2155 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2158 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2160 modest_mail_operation_notify_start (self);
2161 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2162 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2165 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2167 g_object_unref (parent);
2169 g_warning ("%s: could not get parent folder", __FUNCTION__);
2173 /* Notify about operation end */
2174 modest_mail_operation_notify_end (self);
2178 transfer_folder_status_cb (GObject *obj,
2182 ModestMailOperation *self;
2183 ModestMailOperationPrivate *priv;
2184 ModestMailOperationState *state;
2185 XFerFolderAsyncHelper *helper;
2187 g_return_if_fail (status != NULL);
2189 /* Show only the status information we want */
2190 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2193 helper = (XFerFolderAsyncHelper *) user_data;
2194 g_return_if_fail (helper != NULL);
2196 self = helper->mail_op;
2197 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2199 priv->done = status->position;
2200 priv->total = status->of_total;
2202 state = modest_mail_operation_clone_state (self);
2204 /* This is not a GDK lock because we are a Tinymail callback
2205 * which is already GDK locked by Tinymail */
2207 /* no gdk_threads_enter (), CHECKED */
2209 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2211 /* no gdk_threads_leave (), CHECKED */
2213 g_slice_free (ModestMailOperationState, state);
2217 transfer_folder_cb (TnyFolder *folder,
2219 TnyFolderStore *into,
2220 TnyFolder *new_folder,
2224 XFerFolderAsyncHelper *helper;
2225 ModestMailOperation *self = NULL;
2226 ModestMailOperationPrivate *priv = NULL;
2228 helper = (XFerFolderAsyncHelper *) user_data;
2229 g_return_if_fail (helper != NULL);
2231 self = helper->mail_op;
2232 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2235 priv->error = g_error_copy (err);
2237 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2238 } else if (cancelled) {
2239 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2240 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2241 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2242 _("Transference of %s was cancelled."),
2243 tny_folder_get_name (folder));
2246 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2249 /* Update state of new folder */
2251 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2252 tny_folder_poke_status (new_folder);
2255 /* Notify about operation end */
2256 modest_mail_operation_notify_end (self);
2258 /* If user defined callback function was defined, call it */
2259 if (helper->user_callback) {
2261 /* This is not a GDK lock because we are a Tinymail callback
2262 * which is already GDK locked by Tinymail */
2264 /* no gdk_threads_enter (), CHECKED */
2265 helper->user_callback (self, new_folder, helper->user_data);
2266 /* no gdk_threads_leave () , CHECKED */
2270 g_object_unref (helper->mail_op);
2271 g_slice_free (XFerFolderAsyncHelper, helper);
2276 * This function checks if the new name is a valid name for our local
2277 * folders account. The new name could not be the same than then name
2278 * of any of the mandatory local folders
2280 * We can not rely on tinymail because tinymail does not check the
2281 * name of the virtual folders that the account could have in the case
2282 * that we're doing a rename (because it directly calls Camel which
2283 * knows nothing about our virtual folders).
2285 * In the case of an actual copy/move (i.e. move/copy a folder between
2286 * accounts) tinymail uses the tny_folder_store_create_account which
2287 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2288 * checks the new name of the folder, so this call in that case
2289 * wouldn't be needed. *But* NOTE that if tinymail changes its
2290 * implementation (if folder transfers within the same account is no
2291 * longer implemented as a rename) this call will allow Modest to work
2294 * If the new name is not valid, this function will set the status to
2295 * failed and will set also an error in the mail operation
2298 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2299 TnyFolderStore *into,
2300 const gchar *new_name)
2302 if (TNY_IS_ACCOUNT (into) &&
2303 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2304 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2306 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2307 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2308 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2309 _CS("ckdg_ib_folder_already_exists"));
2316 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2318 TnyFolderStore *parent,
2319 gboolean delete_original,
2320 XferFolderAsyncUserCallback user_callback,
2323 ModestMailOperationPrivate *priv = NULL;
2324 ModestTnyFolderRules parent_rules = 0, rules;
2325 XFerFolderAsyncHelper *helper = NULL;
2326 const gchar *folder_name = NULL;
2327 const gchar *error_msg;
2329 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2330 g_return_if_fail (TNY_IS_FOLDER (folder));
2331 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2333 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2334 folder_name = tny_folder_get_name (folder);
2336 /* Set the error msg */
2337 error_msg = _("mail_in_ui_folder_move_target_error");
2339 /* Get account and set it into mail_operation */
2340 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2341 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2342 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2344 /* Get folder rules */
2345 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2346 if (TNY_IS_FOLDER (parent))
2347 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2349 /* Apply operation constraints */
2350 if ((gpointer) parent == (gpointer) folder ||
2351 (!TNY_IS_FOLDER_STORE (parent)) ||
2352 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2355 } else if (TNY_IS_FOLDER (parent) &&
2356 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2360 } else if (TNY_IS_FOLDER (parent) &&
2361 TNY_IS_FOLDER_STORE (folder) &&
2362 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2363 TNY_FOLDER_STORE (folder))) {
2364 /* Do not move a parent into a child */
2366 } else if (TNY_IS_FOLDER_STORE (parent) &&
2367 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2368 /* Check that the new folder name is not used by any
2371 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2372 /* Check that the new folder name is not used by any
2373 special local folder */
2376 /* Create the helper */
2377 helper = g_slice_new0 (XFerFolderAsyncHelper);
2378 helper->mail_op = g_object_ref (self);
2379 helper->user_callback = user_callback;
2380 helper->user_data = user_data;
2382 /* Move/Copy folder */
2383 modest_mail_operation_notify_start (self);
2384 tny_folder_copy_async (folder,
2386 tny_folder_get_name (folder),
2389 transfer_folder_status_cb,
2395 /* Set status failed and set an error */
2396 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2397 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2398 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2401 /* Call the user callback if exists */
2403 user_callback (self, NULL, user_data);
2405 /* Notify the queue */
2406 modest_mail_operation_notify_end (self);
2410 modest_mail_operation_rename_folder (ModestMailOperation *self,
2413 XferFolderAsyncUserCallback user_callback,
2416 ModestMailOperationPrivate *priv;
2417 ModestTnyFolderRules rules;
2418 XFerFolderAsyncHelper *helper;
2420 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2421 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2422 g_return_if_fail (name);
2424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2426 /* Get account and set it into mail_operation */
2427 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2428 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2430 /* Check folder rules */
2431 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2432 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2434 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2437 TnyFolderStore *into;
2439 into = tny_folder_get_folder_store (folder);
2441 /* Check that the new folder name is not used by any
2442 special local folder */
2443 if (new_name_valid_if_local_account (priv, into, name)) {
2444 /* Create the helper */
2445 helper = g_slice_new0 (XFerFolderAsyncHelper);
2446 helper->mail_op = g_object_ref(self);
2447 helper->user_callback = user_callback;
2448 helper->user_data = user_data;
2450 /* Rename. Camel handles folder subscription/unsubscription */
2451 modest_mail_operation_notify_start (self);
2452 tny_folder_copy_async (folder, into, name, TRUE,
2454 transfer_folder_status_cb,
2456 g_object_unref (into);
2458 g_object_unref (into);
2465 /* Set status failed and set an error */
2466 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2467 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2468 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2469 _("FIXME: unable to rename"));
2472 user_callback (self, NULL, user_data);
2474 /* Notify about operation end */
2475 modest_mail_operation_notify_end (self);
2478 /* ******************************************************************* */
2479 /* ************************** MSG ACTIONS ************************* */
2480 /* ******************************************************************* */
2483 modest_mail_operation_get_msg (ModestMailOperation *self,
2485 gboolean progress_feedback,
2486 GetMsgAsyncUserCallback user_callback,
2489 GetMsgInfo *helper = NULL;
2491 ModestMailOperationPrivate *priv;
2493 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2494 g_return_if_fail (TNY_IS_HEADER (header));
2496 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2497 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2501 /* Check memory low */
2502 if (_check_memory_low (self)) {
2504 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2505 modest_mail_operation_notify_end (self);
2509 /* Get account and set it into mail_operation */
2510 folder = tny_header_get_folder (header);
2511 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2513 /* Check for cached messages */
2514 if (progress_feedback) {
2515 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2516 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2518 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2520 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2523 /* Create the helper */
2524 helper = g_slice_new0 (GetMsgInfo);
2525 helper->header = g_object_ref (header);
2526 helper->mail_op = g_object_ref (self);
2527 helper->user_callback = user_callback;
2528 helper->user_data = user_data;
2529 helper->destroy_notify = NULL;
2530 helper->last_total_bytes = 0;
2531 helper->sum_total_bytes = 0;
2532 helper->total_bytes = tny_header_get_message_size (header);
2533 helper->more_msgs = NULL;
2535 modest_mail_operation_notify_start (self);
2537 /* notify about the start of the operation */
2538 ModestMailOperationState *state;
2539 state = modest_mail_operation_clone_state (self);
2542 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2544 g_slice_free (ModestMailOperationState, state);
2546 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2548 g_object_unref (G_OBJECT (folder));
2552 get_msg_status_cb (GObject *obj,
2556 GetMsgInfo *helper = NULL;
2558 g_return_if_fail (status != NULL);
2560 /* Show only the status information we want */
2561 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2564 helper = (GetMsgInfo *) user_data;
2565 g_return_if_fail (helper != NULL);
2567 /* Notify progress */
2568 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2569 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2573 get_msg_async_cb (TnyFolder *folder,
2579 GetMsgInfo *info = NULL;
2580 ModestMailOperationPrivate *priv = NULL;
2583 info = (GetMsgInfo *) user_data;
2585 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2588 if (info->more_msgs) {
2589 tny_iterator_next (info->more_msgs);
2590 finished = (tny_iterator_is_done (info->more_msgs));
2592 finished = (priv->done == priv->total) ? TRUE : FALSE;
2595 /* If canceled by the user, ignore the error given by Tinymail */
2599 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2601 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2602 priv->error = g_error_copy ((const GError *) err);
2604 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2606 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2607 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2610 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2611 /* Set the success status before calling the user callback */
2612 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2616 /* Call the user callback */
2617 if (info->user_callback)
2618 info->user_callback (info->mail_op, info->header, canceled,
2619 msg, err, info->user_data);
2621 /* Notify about operation end if this is the last callback */
2623 /* Free user data */
2624 if (info->destroy_notify)
2625 info->destroy_notify (info->user_data);
2627 /* Notify about operation end */
2628 modest_mail_operation_notify_end (info->mail_op);
2631 if (info->more_msgs)
2632 g_object_unref (info->more_msgs);
2633 g_object_unref (info->header);
2634 g_object_unref (info->mail_op);
2635 g_slice_free (GetMsgInfo, info);
2636 } else if (info->more_msgs) {
2637 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2638 TnyFolder *folder = tny_header_get_folder (header);
2640 g_object_unref (info->header);
2641 info->header = g_object_ref (header);
2643 /* Retrieve the next message */
2644 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2646 g_object_unref (header);
2647 g_object_unref (folder);
2649 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2654 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2655 TnyList *header_list,
2656 GetMsgAsyncUserCallback user_callback,
2658 GDestroyNotify notify)
2660 ModestMailOperationPrivate *priv = NULL;
2662 TnyIterator *iter = NULL;
2663 gboolean has_uncached_messages;
2665 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2667 /* Init mail operation */
2668 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2669 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2671 priv->total = tny_list_get_length(header_list);
2673 /* Check memory low */
2674 if (_check_memory_low (self)) {
2675 if (user_callback) {
2676 TnyHeader *header = NULL;
2679 if (tny_list_get_length (header_list) > 0) {
2680 iter = tny_list_create_iterator (header_list);
2681 header = (TnyHeader *) tny_iterator_get_current (iter);
2682 g_object_unref (iter);
2684 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2686 g_object_unref (header);
2690 /* Notify about operation end */
2691 modest_mail_operation_notify_end (self);
2695 /* Check uncached messages */
2696 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2697 !has_uncached_messages && !tny_iterator_is_done (iter);
2698 tny_iterator_next (iter)) {
2701 header = (TnyHeader *) tny_iterator_get_current (iter);
2702 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2703 has_uncached_messages = TRUE;
2704 g_object_unref (header);
2706 g_object_unref (iter);
2707 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2709 /* Get account and set it into mail_operation */
2710 if (tny_list_get_length (header_list) >= 1) {
2711 TnyIterator *iterator = tny_list_create_iterator (header_list);
2712 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2714 TnyFolder *folder = tny_header_get_folder (header);
2716 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2717 g_object_unref (folder);
2719 g_object_unref (header);
2721 g_object_unref (iterator);
2724 msg_list_size = compute_message_list_size (header_list, 0);
2726 modest_mail_operation_notify_start (self);
2727 iter = tny_list_create_iterator (header_list);
2728 if (!tny_iterator_is_done (iter)) {
2729 /* notify about the start of the operation */
2730 ModestMailOperationState *state;
2731 state = modest_mail_operation_clone_state (self);
2734 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2737 GetMsgInfo *msg_info = NULL;
2738 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2739 TnyFolder *folder = tny_header_get_folder (header);
2741 /* Create the message info */
2742 msg_info = g_slice_new0 (GetMsgInfo);
2743 msg_info->mail_op = g_object_ref (self);
2744 msg_info->header = g_object_ref (header);
2745 msg_info->more_msgs = g_object_ref (iter);
2746 msg_info->user_callback = user_callback;
2747 msg_info->user_data = user_data;
2748 msg_info->destroy_notify = notify;
2749 msg_info->last_total_bytes = 0;
2750 msg_info->sum_total_bytes = 0;
2751 msg_info->total_bytes = msg_list_size;
2753 /* The callback will call it per each header */
2754 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2756 /* Free and go on */
2757 g_object_unref (header);
2758 g_object_unref (folder);
2759 g_slice_free (ModestMailOperationState, state);
2761 g_object_unref (iter);
2766 remove_msgs_async_cb (TnyFolder *folder,
2771 gboolean expunge, leave_on_server;
2772 const gchar *account_name;
2773 TnyAccount *account;
2774 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
2775 ModestMailOperation *self;
2776 ModestMailOperationPrivate *priv;
2777 ModestProtocolRegistry *protocol_registry;
2779 self = (ModestMailOperation *) user_data;
2780 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2781 protocol_registry = modest_runtime_get_protocol_registry ();
2783 if (canceled || err) {
2784 /* If canceled by the user, ignore the error given by Tinymail */
2786 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2788 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2789 priv->error = g_error_copy ((const GError *) err);
2790 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2793 modest_mail_operation_notify_end (self);
2794 g_object_unref (self);
2798 account = tny_folder_get_account (folder);
2799 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2801 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2803 account_proto = modest_tny_account_get_protocol_type (account);
2804 g_object_unref (account);
2806 if ((modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto) &&
2807 !leave_on_server) ||
2808 !modest_tny_folder_is_remote_folder (folder))
2814 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback,
2819 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2821 gboolean remove_to_trash /*ignored*/)
2823 TnyFolder *folder = NULL;
2824 ModestMailOperationPrivate *priv;
2825 TnyIterator *iter = NULL;
2826 TnyHeader *header = NULL;
2827 TnyList *remove_headers = NULL;
2828 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2830 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2831 g_return_if_fail (TNY_IS_LIST (headers));
2833 if (remove_to_trash)
2834 g_warning ("remove to trash is not implemented");
2836 if (tny_list_get_length(headers) == 0) {
2837 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2838 goto cleanup; /* nothing to do */
2841 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2842 remove_headers = g_object_ref(headers);
2844 /* Get folder from first header and sync it */
2845 iter = tny_list_create_iterator (headers);
2846 header = TNY_HEADER (tny_iterator_get_current (iter));
2848 folder = tny_header_get_folder (header);
2849 if (!TNY_IS_FOLDER(folder)) {
2850 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2854 /* Don't remove messages that are being sent */
2855 if (modest_tny_folder_is_local_folder (folder)) {
2856 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2858 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2859 TnyTransportAccount *traccount = NULL;
2860 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2861 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2863 ModestTnySendQueueStatus status;
2864 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount, TRUE);
2866 if (TNY_IS_SEND_QUEUE (send_queue)) {
2867 TnyIterator *iter = tny_list_create_iterator(headers);
2868 g_object_unref(remove_headers);
2869 remove_headers = TNY_LIST(tny_simple_list_new());
2870 while (!tny_iterator_is_done(iter)) {
2872 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2873 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2874 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2875 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2876 tny_list_append(remove_headers, G_OBJECT(hdr));
2878 g_object_unref(hdr);
2880 tny_iterator_next(iter);
2882 g_object_unref(iter);
2884 g_object_unref(traccount);
2888 /* Get account and set it into mail_operation */
2889 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2890 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2891 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2893 /* remove message from folder */
2894 modest_mail_operation_notify_start (self);
2895 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
2896 NULL, g_object_ref (self));
2900 g_object_unref (remove_headers);
2902 g_object_unref (header);
2904 g_object_unref (iter);
2906 g_object_unref (folder);
2910 notify_progress_of_multiple_messages (ModestMailOperation *self,
2912 gint *last_total_bytes,
2913 gint *sum_total_bytes,
2915 gboolean increment_done)
2917 ModestMailOperationPrivate *priv;
2918 ModestMailOperationState *state;
2919 gboolean is_num_bytes = FALSE;
2921 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2923 /* We know that tinymail sends us information about
2924 * transferred bytes with this particular message
2926 if (status->message)
2927 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2929 state = modest_mail_operation_clone_state (self);
2930 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2931 /* We know that we're in a different message when the
2932 total number of bytes to transfer is different. Of
2933 course it could fail if we're transferring messages
2934 of the same size, but this is a workarround */
2935 if (status->of_total != *last_total_bytes) {
2936 /* We need to increment the done when there is
2937 no information about each individual
2938 message, we need to do this in message
2939 transfers, and we don't do it for getting
2943 *sum_total_bytes += *last_total_bytes;
2944 *last_total_bytes = status->of_total;
2946 state->bytes_done += status->position + *sum_total_bytes;
2947 state->bytes_total = total_bytes;
2949 /* Notify the status change. Only notify about changes
2950 referred to bytes */
2951 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2955 g_slice_free (ModestMailOperationState, state);
2959 transfer_msgs_status_cb (GObject *obj,
2963 XFerMsgsAsyncHelper *helper;
2965 g_return_if_fail (status != NULL);
2967 /* Show only the status information we want */
2968 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2971 helper = (XFerMsgsAsyncHelper *) user_data;
2972 g_return_if_fail (helper != NULL);
2974 /* Notify progress */
2975 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2976 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2980 transfer_msgs_sync_folder_cb (TnyFolder *self,
2985 XFerMsgsAsyncHelper *helper;
2986 /* We don't care here about the results of the
2988 helper = (XFerMsgsAsyncHelper *) user_data;
2990 /* Notify about operation end */
2991 modest_mail_operation_notify_end (helper->mail_op);
2993 /* If user defined callback function was defined, call it */
2994 if (helper->user_callback)
2995 helper->user_callback (helper->mail_op, helper->user_data);
2998 if (helper->more_msgs)
2999 g_object_unref (helper->more_msgs);
3000 if (helper->headers)
3001 g_object_unref (helper->headers);
3002 if (helper->dest_folder)
3003 g_object_unref (helper->dest_folder);
3004 if (helper->mail_op)
3005 g_object_unref (helper->mail_op);
3006 g_slice_free (XFerMsgsAsyncHelper, helper);
3010 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3012 XFerMsgsAsyncHelper *helper;
3013 ModestMailOperation *self;
3014 ModestMailOperationPrivate *priv;
3015 gboolean finished = TRUE;
3017 helper = (XFerMsgsAsyncHelper *) user_data;
3018 self = helper->mail_op;
3020 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3023 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3025 priv->error = g_error_copy (err);
3027 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3028 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3029 if (helper->more_msgs) {
3030 /* We'll transfer the next message in the list */
3031 tny_iterator_next (helper->more_msgs);
3032 if (!tny_iterator_is_done (helper->more_msgs)) {
3033 GObject *next_header;
3034 g_object_unref (helper->headers);
3035 helper->headers = tny_simple_list_new ();
3036 next_header = tny_iterator_get_current (helper->more_msgs);
3037 tny_list_append (helper->headers, next_header);
3038 g_object_unref (next_header);
3044 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3049 /* Synchronize the source folder contents. This should
3050 be done by tinymail but the camel_folder_sync it's
3051 actually disabled in transfer_msgs_thread_clean
3052 because it's supposed to cause hangs */
3053 tny_folder_sync_async (folder, helper->delete,
3054 transfer_msgs_sync_folder_cb,
3057 /* Transfer more messages */
3058 tny_folder_transfer_msgs_async (folder,
3060 helper->dest_folder,
3063 transfer_msgs_status_cb,
3068 /* Computes the size of the messages the headers in the list belongs
3069 to. If num_elements is different from 0 then it only takes into
3070 account the first num_elements for the calculation */
3072 compute_message_list_size (TnyList *headers,
3076 guint size = 0, element = 0;
3078 /* If num_elements is not valid then take all into account */
3079 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3080 num_elements = tny_list_get_length (headers);
3082 iter = tny_list_create_iterator (headers);
3083 while (!tny_iterator_is_done (iter) && element < num_elements) {
3084 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3085 size += tny_header_get_message_size (header);
3086 g_object_unref (header);
3087 tny_iterator_next (iter);
3090 g_object_unref (iter);
3096 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3099 gboolean delete_original,
3100 XferMsgsAsyncUserCallback user_callback,
3103 ModestMailOperationPrivate *priv = NULL;
3104 TnyIterator *iter = NULL;
3105 TnyFolder *src_folder = NULL;
3106 XFerMsgsAsyncHelper *helper = NULL;
3107 TnyHeader *header = NULL;
3108 ModestTnyFolderRules rules = 0;
3109 TnyAccount *dst_account = NULL;
3110 gboolean leave_on_server;
3111 ModestMailOperationState *state;
3112 ModestProtocolRegistry *protocol_registry;
3113 ModestProtocolType account_protocol;
3115 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3116 g_return_if_fail (headers && TNY_IS_LIST (headers));
3117 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3120 protocol_registry = modest_runtime_get_protocol_registry ();
3122 priv->total = tny_list_get_length (headers);
3124 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3125 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3127 /* Apply folder rules */
3128 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3129 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3130 /* Set status failed and set an error */
3131 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3132 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3133 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3134 _CS("ckct_ib_unable_to_paste_here"));
3135 /* Notify the queue */
3136 modest_mail_operation_notify_end (self);
3140 /* Get source folder */
3141 iter = tny_list_create_iterator (headers);
3142 header = TNY_HEADER (tny_iterator_get_current (iter));
3144 src_folder = tny_header_get_folder (header);
3145 g_object_unref (header);
3147 g_object_unref (iter);
3149 if (src_folder == NULL) {
3150 /* Notify the queue */
3151 modest_mail_operation_notify_end (self);
3153 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3158 /* Check folder source and destination */
3159 if (src_folder == folder) {
3160 /* Set status failed and set an error */
3161 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3162 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3163 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3164 _("mail_in_ui_folder_copy_target_error"));
3166 /* Notify the queue */
3167 modest_mail_operation_notify_end (self);
3170 g_object_unref (src_folder);
3174 /* Create the helper */
3175 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3176 helper->mail_op = g_object_ref(self);
3177 helper->dest_folder = g_object_ref(folder);
3178 helper->user_callback = user_callback;
3179 helper->user_data = user_data;
3180 helper->last_total_bytes = 0;
3181 helper->sum_total_bytes = 0;
3182 helper->total_bytes = compute_message_list_size (headers, 0);
3184 /* Get account and set it into mail_operation */
3185 priv->account = modest_tny_folder_get_account (src_folder);
3186 dst_account = modest_tny_folder_get_account (folder);
3188 if (priv->account == dst_account) {
3189 /* Transfer all messages at once using the fast
3190 * method. Note that depending on the server this
3191 * might not be that fast, and might not be
3192 * user-cancellable either */
3193 helper->headers = g_object_ref (headers);
3194 helper->more_msgs = NULL;
3196 /* Transfer messages one by one so the user can cancel
3199 helper->headers = tny_simple_list_new ();
3200 helper->more_msgs = tny_list_create_iterator (headers);
3201 hdr = tny_iterator_get_current (helper->more_msgs);
3202 tny_list_append (helper->headers, hdr);
3203 g_object_unref (hdr);
3206 /* If leave_on_server is set to TRUE then don't use
3207 delete_original, we always pass FALSE. This is because
3208 otherwise tinymail will try to sync the source folder and
3209 this could cause an error if we're offline while
3210 transferring an already downloaded message from a POP
3212 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3213 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3214 const gchar *account_name;
3216 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3217 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3220 leave_on_server = FALSE;
3223 /* Do not delete messages if leave on server is TRUE */
3224 helper->delete = (leave_on_server) ? FALSE : delete_original;
3226 modest_mail_operation_notify_start (self);
3228 /* Start notifying progress */
3229 state = modest_mail_operation_clone_state (self);
3232 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3233 g_slice_free (ModestMailOperationState, state);
3235 tny_folder_transfer_msgs_async (src_folder,
3240 transfer_msgs_status_cb,
3242 g_object_unref (src_folder);
3243 g_object_unref (dst_account);
3248 on_refresh_folder (TnyFolder *folder,
3253 RefreshAsyncHelper *helper = NULL;
3254 ModestMailOperation *self = NULL;
3255 ModestMailOperationPrivate *priv = NULL;
3257 helper = (RefreshAsyncHelper *) user_data;
3258 self = helper->mail_op;
3259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3261 g_return_if_fail(priv!=NULL);
3264 priv->error = g_error_copy (error);
3265 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3270 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3271 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3272 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3273 _("Error trying to refresh the contents of %s"),
3274 tny_folder_get_name (folder));
3278 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3281 /* Call user defined callback, if it exists */
3282 if (helper->user_callback) {
3284 /* This is not a GDK lock because we are a Tinymail callback and
3285 * Tinymail already acquires the Gdk lock */
3286 helper->user_callback (self, folder, helper->user_data);
3290 g_slice_free (RefreshAsyncHelper, helper);
3292 /* Notify about operation end */
3293 modest_mail_operation_notify_end (self);
3294 g_object_unref(self);
3298 on_refresh_folder_status_update (GObject *obj,
3302 RefreshAsyncHelper *helper = NULL;
3303 ModestMailOperation *self = NULL;
3304 ModestMailOperationPrivate *priv = NULL;
3305 ModestMailOperationState *state;
3307 g_return_if_fail (user_data != NULL);
3308 g_return_if_fail (status != NULL);
3310 /* Show only the status information we want */
3311 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3314 helper = (RefreshAsyncHelper *) user_data;
3315 self = helper->mail_op;
3316 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3318 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3320 priv->done = status->position;
3321 priv->total = status->of_total;
3323 state = modest_mail_operation_clone_state (self);
3325 /* This is not a GDK lock because we are a Tinymail callback and
3326 * Tinymail already acquires the Gdk lock */
3327 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3329 g_slice_free (ModestMailOperationState, state);
3333 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3335 RefreshAsyncUserCallback user_callback,
3338 ModestMailOperationPrivate *priv = NULL;
3339 RefreshAsyncHelper *helper = NULL;
3341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3343 /* Check memory low */
3344 if (_check_memory_low (self)) {
3346 user_callback (self, folder, user_data);
3347 /* Notify about operation end */
3348 modest_mail_operation_notify_end (self);
3352 /* Get account and set it into mail_operation */
3353 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3354 priv->account = modest_tny_folder_get_account (folder);
3355 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3357 /* Create the helper */
3358 helper = g_slice_new0 (RefreshAsyncHelper);
3359 helper->mail_op = g_object_ref(self);
3360 helper->user_callback = user_callback;
3361 helper->user_data = user_data;
3363 modest_mail_operation_notify_start (self);
3365 /* notify that the operation was started */
3366 ModestMailOperationState *state;
3367 state = modest_mail_operation_clone_state (self);
3370 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3372 g_slice_free (ModestMailOperationState, state);
3374 tny_folder_refresh_async (folder,
3376 on_refresh_folder_status_update,
3381 run_queue_notify_and_destroy (RunQueueHelper *helper,
3382 ModestMailOperationStatus status)
3384 ModestMailOperationPrivate *priv;
3387 if (helper->error_handler &&
3388 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3389 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3390 if (helper->start_handler &&
3391 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3392 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3393 if (helper->stop_handler &&
3394 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3395 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3398 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3399 priv->status = status;
3402 modest_mail_operation_notify_end (helper->self);
3405 g_object_unref (helper->queue);
3406 g_object_unref (helper->self);
3407 g_slice_free (RunQueueHelper, helper);
3411 run_queue_stop (ModestTnySendQueue *queue,
3414 RunQueueHelper *helper;
3416 g_debug ("%s sending queue stopped", __FUNCTION__);
3418 helper = (RunQueueHelper *) user_data;
3419 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3423 modest_mail_operation_run_queue (ModestMailOperation *self,
3424 ModestTnySendQueue *queue)
3426 ModestMailOperationPrivate *priv;
3427 RunQueueHelper *helper;
3429 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3430 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3431 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3433 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3434 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3435 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3437 /* Create the helper */
3438 helper = g_slice_new0 (RunQueueHelper);
3439 helper->queue = g_object_ref (queue);
3440 helper->self = g_object_ref (self);
3441 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3442 G_CALLBACK (run_queue_stop),
3445 /* Notify operation has started */
3446 modest_mail_operation_notify_start (self);
3447 g_debug ("%s, run queue started", __FUNCTION__);
3451 queue_wakeup_callback (ModestTnySendQueue *queue,
3456 ModestMailOperation *mail_op;
3457 ModestMailOperationPrivate *priv;
3459 mail_op = (ModestMailOperation *) userdata;
3460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3462 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3463 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3466 modest_mail_operation_notify_end (mail_op);
3467 g_object_unref (mail_op);
3471 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3472 ModestTnySendQueue *queue)
3474 ModestMailOperationPrivate *priv;
3476 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3477 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3478 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3480 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3481 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3482 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3484 g_object_ref (self);
3486 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3487 modest_mail_operation_notify_start (self);
3491 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3493 ModestMailOperation *self = (ModestMailOperation *) userdata;
3494 ModestMailOperationPrivate *priv;
3496 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3497 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3498 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3500 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3502 modest_mail_operation_notify_end (self);
3503 g_object_unref (self);
3507 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3509 ModestMailOperationPrivate *priv;
3511 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3512 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3513 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3515 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3517 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3518 priv->account = NULL;
3519 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3521 modest_mail_operation_notify_start (self);
3522 g_object_ref (self);
3523 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3527 sync_folder_finish_callback (TnyFolder *self,
3533 ModestMailOperation *mail_op;
3534 ModestMailOperationPrivate *priv;
3536 mail_op = (ModestMailOperation *) user_data;
3537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3539 /* If canceled by the user, ignore the error given by Tinymail */
3541 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3543 /* If the operation was a sync then the status is
3544 failed, but if it's part of another operation then
3545 just set it as finished with errors */
3546 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3547 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3549 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3550 priv->error = g_error_copy ((const GError *) err);
3551 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3553 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3556 modest_mail_operation_notify_end (mail_op);
3557 g_object_unref (mail_op);
3561 modest_mail_operation_sync_folder (ModestMailOperation *self,
3562 TnyFolder *folder, gboolean expunge)
3564 ModestMailOperationPrivate *priv;
3566 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3567 g_return_if_fail (TNY_IS_FOLDER (folder));
3568 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3570 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3571 priv->account = modest_tny_folder_get_account (folder);
3572 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3574 modest_mail_operation_notify_start (self);
3575 g_object_ref (self);
3576 tny_folder_sync_async (folder, expunge,
3577 (TnyFolderCallback) sync_folder_finish_callback,
3582 modest_mail_operation_notify_start (ModestMailOperation *self)
3584 ModestMailOperationPrivate *priv = NULL;
3586 g_return_if_fail (self);
3588 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3590 /* Ensure that all the fields are filled correctly */
3591 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3593 /* Notify the observers about the mail operation. We do not
3594 wrapp this emission because we assume that this function is
3595 always called from within the main lock */
3596 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3601 * It's used by the mail operation queue to notify the observers
3602 * attached to that signal that the operation finished. We need to use
3603 * that because tinymail does not give us the progress of a given
3604 * operation when it finishes (it directly calls the operation
3608 modest_mail_operation_notify_end (ModestMailOperation *self)
3610 ModestMailOperationPrivate *priv = NULL;
3612 g_return_if_fail (self);
3614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3616 /* Notify the observers about the mail operation end. We do
3617 not wrapp this emission because we assume that this
3618 function is always called from within the main lock */
3619 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3621 /* Remove the error user data */
3622 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3623 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3627 modest_mail_operation_get_account (ModestMailOperation *self)
3629 ModestMailOperationPrivate *priv = NULL;
3631 g_return_val_if_fail (self, NULL);
3633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3635 return (priv->account) ? g_object_ref (priv->account) : NULL;
3639 modest_mail_operation_noop (ModestMailOperation *self)
3641 ModestMailOperationPrivate *priv = NULL;
3643 g_return_if_fail (self);
3645 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3646 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3647 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3651 /* This mail operation does nothing actually */
3652 modest_mail_operation_notify_start (self);
3653 modest_mail_operation_notify_end (self);
3658 modest_mail_operation_to_string (ModestMailOperation *self)
3660 const gchar *type, *status, *account_id;
3661 ModestMailOperationPrivate *priv = NULL;
3663 g_return_val_if_fail (self, NULL);
3665 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3667 /* new operations don't have anything interesting */
3668 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3669 return g_strdup_printf ("%p <new operation>", self);
3671 switch (priv->op_type) {
3672 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3673 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3674 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3675 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3676 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3677 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3678 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3679 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3680 default: type = "UNEXPECTED"; break;
3683 switch (priv->status) {
3684 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3685 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3686 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3687 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3688 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3689 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3690 default: status= "UNEXPECTED"; break;
3693 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3695 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3696 priv->done, priv->total,
3697 priv->error && priv->error->message ? priv->error->message : "");
3701 * Once the mail operations were objects this will be no longer
3702 * needed. I don't like it, but we need it for the moment
3705 _check_memory_low (ModestMailOperation *mail_op)
3707 if (modest_platform_check_memory_low (NULL, FALSE)) {
3708 ModestMailOperationPrivate *priv;
3710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3711 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3712 g_set_error (&(priv->error),
3713 MODEST_MAIL_OPERATION_ERROR,
3714 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
3715 "Not enough memory to complete the operation");