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"
66 #ifdef MODEST_USE_LIBTIME
67 #include <clockd/libtime.h>
69 #include "modest-account-protocol.h"
70 #include <camel/camel-stream-null.h>
71 #include <widgets/modest-msg-view-window.h>
76 * Remove all these #ifdef stuff when the tinymail's idle calls become
79 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
81 /* 'private'/'protected' functions */
82 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
83 static void modest_mail_operation_init (ModestMailOperation *obj);
84 static void modest_mail_operation_finalize (GObject *obj);
86 static void get_msg_async_cb (TnyFolder *folder,
92 static void get_msg_status_cb (GObject *obj,
96 static void modest_mail_operation_notify_start (ModestMailOperation *self);
97 static void modest_mail_operation_notify_end (ModestMailOperation *self);
99 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
101 gint *last_total_bytes,
102 gint *sum_total_bytes,
104 gboolean increment_done);
106 static guint compute_message_list_size (TnyList *headers, guint num_elements);
108 static int compare_headers_by_date (gconstpointer a,
111 static void sync_folder_finish_callback (TnyFolder *self,
116 static gboolean _check_memory_low (ModestMailOperation *mail_op);
120 ModestTnySendQueue *queue;
121 ModestMailOperation *self;
127 static void run_queue_notify_and_destroy (RunQueueHelper *helper,
128 ModestMailOperationStatus status);
130 /* Helpers for the update account operation (send & receive)*/
133 ModestMailOperation *mail_op;
135 UpdateAccountCallback callback;
140 TnyFolderObserver *inbox_observer;
141 gboolean interactive;
145 static void destroy_update_account_info (UpdateAccountInfo *info);
147 static void update_account_send_mail (UpdateAccountInfo *info);
149 static void update_account_get_msg_async_cb (TnyFolder *folder,
155 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
156 TnyList *new_headers);
158 enum _ModestMailOperationSignals
160 PROGRESS_CHANGED_SIGNAL,
161 OPERATION_STARTED_SIGNAL,
162 OPERATION_FINISHED_SIGNAL,
166 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
167 struct _ModestMailOperationPrivate {
173 ErrorCheckingUserCallback error_checking;
174 gpointer error_checking_user_data;
175 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
176 ModestMailOperationStatus status;
177 ModestMailOperationTypeOperation op_type;
180 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
181 MODEST_TYPE_MAIL_OPERATION, \
182 ModestMailOperationPrivate))
184 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
185 priv->status = new_status;\
190 GetMsgAsyncUserCallback user_callback;
192 TnyIterator *more_msgs;
194 ModestMailOperation *mail_op;
195 GDestroyNotify destroy_notify;
196 gint last_total_bytes;
197 gint sum_total_bytes;
199 TnyIterator *get_parts;
203 typedef struct _RefreshAsyncHelper {
204 ModestMailOperation *mail_op;
205 RefreshAsyncUserCallback user_callback;
207 } RefreshAsyncHelper;
209 typedef struct _XFerMsgsAsyncHelper
211 ModestMailOperation *mail_op;
213 TnyIterator *more_msgs;
214 TnyFolder *dest_folder;
215 XferMsgsAsyncUserCallback user_callback;
218 gint last_total_bytes;
219 gint sum_total_bytes;
221 } XFerMsgsAsyncHelper;
223 typedef struct _XFerFolderAsyncHelper
225 ModestMailOperation *mail_op;
226 XferFolderAsyncUserCallback user_callback;
228 } XFerFolderAsyncHelper;
230 typedef struct _SyncFolderHelper {
231 ModestMailOperation *mail_op;
232 SyncFolderCallback user_callback;
236 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
240 static void modest_mail_operation_create_msg (ModestMailOperation *self,
241 const gchar *from, const gchar *to,
242 const gchar *cc, const gchar *bcc,
243 const gchar *subject, const gchar *plain_body,
244 const gchar *html_body, const GList *attachments_list,
245 const GList *images_list,
246 TnyHeaderFlags priority_flags,
247 const gchar *references, const gchar *in_reply_to,
248 ModestMailOperationCreateMsgCallback callback,
251 static gboolean idle_notify_queue (gpointer data);
254 ModestMailOperation *mail_op;
264 GList *attachments_list;
266 TnyHeaderFlags priority_flags;
267 ModestMailOperationCreateMsgCallback callback;
273 ModestMailOperation *mail_op;
275 ModestMailOperationCreateMsgCallback callback;
280 static GObjectClass *parent_class = NULL;
282 static guint signals[NUM_SIGNALS] = {0};
285 modest_mail_operation_get_type (void)
287 static GType my_type = 0;
289 static const GTypeInfo my_info = {
290 sizeof(ModestMailOperationClass),
291 NULL, /* base init */
292 NULL, /* base finalize */
293 (GClassInitFunc) modest_mail_operation_class_init,
294 NULL, /* class finalize */
295 NULL, /* class data */
296 sizeof(ModestMailOperation),
298 (GInstanceInitFunc) modest_mail_operation_init,
301 my_type = g_type_register_static (G_TYPE_OBJECT,
302 "ModestMailOperation",
309 modest_mail_operation_class_init (ModestMailOperationClass *klass)
311 GObjectClass *gobject_class;
312 gobject_class = (GObjectClass*) klass;
314 parent_class = g_type_class_peek_parent (klass);
315 gobject_class->finalize = modest_mail_operation_finalize;
317 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
320 * ModestMailOperation::progress-changed
321 * @self: the #MailOperation that emits the signal
322 * @user_data: user data set when the signal handler was connected
324 * Emitted when the progress of a mail operation changes
326 signals[PROGRESS_CHANGED_SIGNAL] =
327 g_signal_new ("progress-changed",
328 G_TYPE_FROM_CLASS (gobject_class),
330 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
332 g_cclosure_marshal_VOID__POINTER,
333 G_TYPE_NONE, 1, G_TYPE_POINTER);
337 * This signal is issued whenever a mail operation starts, and
338 * starts mean when the tinymail operation is issued. This
339 * means that it could happen that something wrong happens and
340 * the tinymail function is never called. In this situation a
341 * operation-finished will be issued without any
344 signals[OPERATION_STARTED_SIGNAL] =
345 g_signal_new ("operation-started",
346 G_TYPE_FROM_CLASS (gobject_class),
348 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
350 g_cclosure_marshal_VOID__VOID,
355 * This signal is issued whenever a mail operation
356 * finishes. Note that this signal could be issued without any
357 * previous "operation-started" signal, because this last one
358 * is only issued when the tinymail operation is successfully
361 signals[OPERATION_FINISHED_SIGNAL] =
362 g_signal_new ("operation-finished",
363 G_TYPE_FROM_CLASS (gobject_class),
365 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
367 g_cclosure_marshal_VOID__VOID,
372 modest_mail_operation_init (ModestMailOperation *obj)
374 ModestMailOperationPrivate *priv;
376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
378 priv->account = NULL;
379 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
380 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
385 priv->error_checking = NULL;
386 priv->error_checking_user_data = NULL;
390 modest_mail_operation_finalize (GObject *obj)
392 ModestMailOperationPrivate *priv;
394 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
399 g_error_free (priv->error);
403 g_object_unref (priv->source);
407 g_object_unref (priv->account);
408 priv->account = NULL;
412 G_OBJECT_CLASS(parent_class)->finalize (obj);
416 modest_mail_operation_new (GObject *source)
418 ModestMailOperation *obj;
419 ModestMailOperationPrivate *priv;
421 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
422 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
425 priv->source = g_object_ref(source);
431 modest_mail_operation_new_with_error_handling (GObject *source,
432 ErrorCheckingUserCallback error_handler,
434 ErrorCheckingUserDataDestroyer error_handler_destroyer)
436 ModestMailOperation *obj;
437 ModestMailOperationPrivate *priv;
439 obj = modest_mail_operation_new (source);
440 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
442 g_return_val_if_fail (error_handler != NULL, obj);
443 priv->error_checking = error_handler;
444 priv->error_checking_user_data = user_data;
445 priv->error_checking_user_data_destroyer = error_handler_destroyer;
451 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
453 ModestMailOperationPrivate *priv;
455 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
458 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
460 /* Call the user callback */
461 if (priv->error_checking != NULL)
462 priv->error_checking (self, priv->error_checking_user_data);
466 ModestMailOperationTypeOperation
467 modest_mail_operation_get_type_operation (ModestMailOperation *self)
469 ModestMailOperationPrivate *priv;
471 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
472 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
474 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
476 return priv->op_type;
480 modest_mail_operation_is_mine (ModestMailOperation *self,
483 ModestMailOperationPrivate *priv;
485 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
488 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
489 if (priv->source == NULL) return FALSE;
491 return priv->source == me;
495 modest_mail_operation_get_source (ModestMailOperation *self)
497 ModestMailOperationPrivate *priv;
499 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
504 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
508 return (priv->source) ? g_object_ref (priv->source) : NULL;
511 ModestMailOperationStatus
512 modest_mail_operation_get_status (ModestMailOperation *self)
514 ModestMailOperationPrivate *priv;
516 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
517 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
518 MODEST_MAIL_OPERATION_STATUS_INVALID);
520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
522 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
523 return MODEST_MAIL_OPERATION_STATUS_INVALID;
530 modest_mail_operation_get_error (ModestMailOperation *self)
532 ModestMailOperationPrivate *priv;
534 g_return_val_if_fail (self, NULL);
535 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
540 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
548 modest_mail_operation_cancel (ModestMailOperation *self)
550 ModestMailOperationPrivate *priv;
551 gboolean canceled = FALSE;
553 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
555 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
558 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
560 /* Cancel the mail operation */
561 g_return_val_if_fail (priv->account, FALSE);
562 tny_account_cancel (priv->account);
564 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
565 ModestTnySendQueue *queue;
566 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
569 /* Cancel the sending of the following next messages */
570 if (TNY_IS_SEND_QUEUE (queue))
571 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
578 modest_mail_operation_get_task_done (ModestMailOperation *self)
580 ModestMailOperationPrivate *priv;
582 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
585 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
590 modest_mail_operation_get_task_total (ModestMailOperation *self)
592 ModestMailOperationPrivate *priv;
594 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
597 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
602 modest_mail_operation_is_finished (ModestMailOperation *self)
604 ModestMailOperationPrivate *priv;
605 gboolean retval = FALSE;
607 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
612 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
613 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
614 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
615 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
625 * Creates an image of the current state of a mail operation, the
626 * caller must free it
628 static ModestMailOperationState *
629 modest_mail_operation_clone_state (ModestMailOperation *self)
631 ModestMailOperationState *state;
632 ModestMailOperationPrivate *priv;
634 g_return_val_if_fail (self, NULL);
635 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
636 g_return_val_if_fail (priv, NULL);
641 state = g_slice_new (ModestMailOperationState);
643 state->status = priv->status;
644 state->op_type = priv->op_type;
645 state->done = priv->done;
646 state->total = priv->total;
647 state->finished = modest_mail_operation_is_finished (self);
648 state->bytes_done = 0;
649 state->bytes_total = 0;
654 /* ******************************************************************* */
655 /* ************************** SEND ACTIONS ************************* */
656 /* ******************************************************************* */
660 ModestMailOperation *mail_op;
665 send_mail_on_sync_async_cb (TnyFolder *folder,
670 ModestMailOperationPrivate *priv;
671 ModestMailOperation *self;
672 SendNewMailHelper *helper;
674 helper = (SendNewMailHelper *) user_data;
675 self = helper->mail_op;
676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
682 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
683 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
684 "Error adding a msg to the send queue\n");
685 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
687 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
692 modest_mail_operation_notify_end (self);
694 g_object_unref (helper->mail_op);
695 g_slice_free (SendNewMailHelper, helper);
699 run_queue_start (TnySendQueue *self,
702 RunQueueHelper *helper = (RunQueueHelper *) user_data;
703 ModestMailOperation *mail_op;
705 g_debug ("%s sending queue successfully started", __FUNCTION__);
707 /* Wait for the message to be sent */
708 mail_op = modest_mail_operation_new (NULL);
709 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
711 modest_mail_operation_run_queue (mail_op, helper->queue);
712 g_object_unref (mail_op);
714 /* Free the helper and end operation */
715 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
719 run_queue_error_happened (TnySendQueue *queue,
725 RunQueueHelper *helper = (RunQueueHelper *) user_data;
726 ModestMailOperationPrivate *priv;
728 /* If we are here this means that the send queue could not
729 start to send emails. Shouldn't happen as this means that
730 we could not create the thread */
731 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
734 priv->error = g_error_copy ((const GError *) error);
736 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
737 /* This code is here for safety reasons. It should
738 never be called, because that would mean that we
739 are not controlling some error case */
740 g_warning ("%s Error %s should not happen",
741 __FUNCTION__, error->message);
744 /* Free helper and end operation */
745 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
749 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
755 ModestMailOperationPrivate *priv;
756 ModestMailOperation *self;
757 SendNewMailHelper *helper;
759 helper = (SendNewMailHelper *) user_data;
760 self = helper->mail_op;
761 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
767 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
768 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
769 "Error adding a msg to the send queue\n");
770 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
772 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
776 if (helper->notify) {
777 TnyTransportAccount *trans_account;
778 ModestTnySendQueue *queue;
780 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
782 queue = modest_runtime_get_send_queue (trans_account, TRUE);
784 RunQueueHelper *helper;
786 /* Create the helper */
787 helper = g_slice_new0 (RunQueueHelper);
788 helper->queue = g_object_ref (queue);
789 helper->self = g_object_ref (self);
791 /* if sending is ongoing wait for the queue to
792 stop. Otherwise wait for the queue-start
793 signal. It could happen that the queue
794 could not start, then check also the error
796 if (modest_tny_send_queue_sending_in_progress (queue)) {
797 run_queue_start (TNY_SEND_QUEUE (queue), helper);
799 helper->start_handler = g_signal_connect (queue, "queue-start",
800 G_CALLBACK (run_queue_start),
802 helper->error_handler = g_signal_connect (queue, "error-happened",
803 G_CALLBACK (run_queue_error_happened),
807 /* Finalize this mail operation */
808 modest_mail_operation_notify_end (self);
810 g_object_unref (trans_account);
812 g_warning ("No transport account for the operation");
816 g_object_unref (helper->mail_op);
817 g_slice_free (SendNewMailHelper, helper);
821 idle_create_msg_cb (gpointer idle_data)
823 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
825 /* This is a GDK lock because we are an idle callback and
826 * info->callback can contain Gtk+ code */
828 gdk_threads_enter (); /* CHECKED */
829 info->callback (info->mail_op, info->msg, info->userdata);
831 g_object_unref (info->mail_op);
833 g_object_unref (info->msg);
834 g_slice_free (CreateMsgIdleInfo, info);
835 gdk_threads_leave (); /* CHECKED */
841 create_msg_thread (gpointer thread_data)
843 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
844 TnyMsg *new_msg = NULL;
845 ModestMailOperationPrivate *priv;
848 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
849 if (info->html_body == NULL) {
850 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
851 info->bcc, info->subject,
852 info->references, info->in_reply_to,
854 info->attachments_list, &attached,
857 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
858 info->bcc, info->subject,
859 info->references, info->in_reply_to,
861 info->plain_body, info->attachments_list,
862 info->images_list, &attached,
869 /* Set priority flags in message */
870 header = tny_msg_get_header (new_msg);
871 tny_header_set_flag (header, info->priority_flags);
873 /* Set attachment flags in message */
874 if (info->attachments_list != NULL && attached > 0)
875 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
877 g_object_unref (G_OBJECT(header));
879 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
881 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
882 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
883 "modest: failed to create a new msg\n");
891 g_free (info->plain_body);
892 g_free (info->html_body);
893 g_free (info->subject);
894 g_free (info->references);
895 g_free (info->in_reply_to);
896 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
897 g_list_free (info->attachments_list);
898 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
899 g_list_free (info->images_list);
901 if (info->callback) {
902 CreateMsgIdleInfo *idle_info;
903 idle_info = g_slice_new0 (CreateMsgIdleInfo);
904 idle_info->mail_op = g_object_ref (info->mail_op);
905 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
906 idle_info->callback = info->callback;
907 idle_info->userdata = info->userdata;
908 g_idle_add (idle_create_msg_cb, idle_info);
910 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
913 g_object_unref (info->mail_op);
914 g_slice_free (CreateMsgInfo, info);
915 if (new_msg) g_object_unref(new_msg);
921 modest_mail_operation_create_msg (ModestMailOperation *self,
922 const gchar *from, const gchar *to,
923 const gchar *cc, const gchar *bcc,
924 const gchar *subject, const gchar *plain_body,
925 const gchar *html_body,
926 const GList *attachments_list,
927 const GList *images_list,
928 TnyHeaderFlags priority_flags,
929 const gchar *references,
930 const gchar *in_reply_to,
931 ModestMailOperationCreateMsgCallback callback,
934 CreateMsgInfo *info = NULL;
936 info = g_slice_new0 (CreateMsgInfo);
937 info->mail_op = g_object_ref (self);
939 info->from = g_strdup (from);
940 info->to = g_strdup (to);
941 info->cc = g_strdup (cc);
942 info->bcc = g_strdup (bcc);
943 info->subject = g_strdup (subject);
944 info->plain_body = g_strdup (plain_body);
945 info->html_body = g_strdup (html_body);
946 info->references = g_strdup (references);
947 info->in_reply_to = g_strdup (in_reply_to);
948 info->attachments_list = g_list_copy ((GList *) attachments_list);
949 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
950 info->images_list = g_list_copy ((GList *) images_list);
951 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
952 info->priority_flags = priority_flags;
954 info->callback = callback;
955 info->userdata = userdata;
957 g_thread_create (create_msg_thread, info, FALSE, NULL);
962 TnyTransportAccount *transport_account;
967 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
971 TnySendQueue *send_queue = NULL;
972 ModestMailOperationPrivate *priv = NULL;
973 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
974 TnyFolder *draft_folder = NULL;
975 TnyFolder *outbox_folder = NULL;
976 TnyHeader *header = NULL;
978 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
981 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
982 modest_mail_operation_notify_end (self);
986 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
987 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
988 modest_mail_operation_notify_end (self);
992 /* Add message to send queue */
993 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
994 if (!TNY_IS_SEND_QUEUE(send_queue)) {
996 g_error_free (priv->error);
999 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1000 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1001 "modest: could not find send queue for account\n");
1002 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1003 modest_mail_operation_notify_end (self);
1006 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
1007 helper->mail_op = g_object_ref (self);
1008 helper->notify = (info->draft_msg == NULL);
1010 /* Add the msg to the queue. The callback will free
1012 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1014 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1018 if (info->draft_msg != NULL) {
1019 TnyList *tmp_headers = NULL;
1020 TnyFolder *folder = NULL;
1021 TnyFolder *src_folder = NULL;
1022 TnyFolderType folder_type;
1023 TnyTransportAccount *transport_account = NULL;
1024 SendNewMailHelper *helper = NULL;
1026 /* To remove the old mail from its source folder, we need to get the
1027 * transport account of the original draft message (the transport account
1028 * might have been changed by the user) */
1029 header = tny_msg_get_header (info->draft_msg);
1030 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1031 modest_runtime_get_account_store(), header);
1032 if (transport_account == NULL)
1033 transport_account = g_object_ref(info->transport_account);
1034 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1035 TNY_FOLDER_TYPE_DRAFTS);
1036 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1037 TNY_FOLDER_TYPE_OUTBOX);
1038 g_object_unref(transport_account);
1040 if (!draft_folder) {
1041 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1043 modest_mail_operation_notify_end (self);
1046 if (!outbox_folder) {
1047 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1049 modest_mail_operation_notify_end (self);
1053 folder = tny_msg_get_folder (info->draft_msg);
1054 if (folder == NULL) {
1055 modest_mail_operation_notify_end (self);
1058 folder_type = modest_tny_folder_guess_folder_type (folder);
1060 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1061 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1063 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1064 src_folder = outbox_folder;
1066 src_folder = draft_folder;
1068 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1069 * because this function requires it to have a UID. */
1070 helper = g_slice_new (SendNewMailHelper);
1071 helper->mail_op = g_object_ref (self);
1072 helper->notify = TRUE;
1074 tmp_headers = tny_simple_list_new ();
1075 tny_list_append (tmp_headers, (GObject*) header);
1076 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1077 g_object_unref (tmp_headers);
1078 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1080 g_object_unref (folder);
1085 g_object_unref (header);
1086 if (info->draft_msg)
1087 g_object_unref (info->draft_msg);
1089 g_object_unref (draft_folder);
1091 g_object_unref (outbox_folder);
1092 if (info->transport_account)
1093 g_object_unref (info->transport_account);
1094 g_slice_free (SendNewMailInfo, info);
1098 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1099 TnyTransportAccount *transport_account,
1101 const gchar *from, const gchar *to,
1102 const gchar *cc, const gchar *bcc,
1103 const gchar *subject, const gchar *plain_body,
1104 const gchar *html_body,
1105 const GList *attachments_list,
1106 const GList *images_list,
1107 const gchar *references,
1108 const gchar *in_reply_to,
1109 TnyHeaderFlags priority_flags)
1111 ModestMailOperationPrivate *priv = NULL;
1112 SendNewMailInfo *info;
1114 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1115 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1117 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1118 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1119 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1120 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1122 modest_mail_operation_notify_start (self);
1124 /* Check parametters */
1126 /* Set status failed and set an error */
1127 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1128 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1129 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1130 _("Error trying to send a mail. You need to set at least one recipient"));
1131 modest_mail_operation_notify_end (self);
1134 info = g_slice_new0 (SendNewMailInfo);
1135 info->transport_account = transport_account;
1136 if (transport_account)
1137 g_object_ref (transport_account);
1138 info->draft_msg = draft_msg;
1140 g_object_ref (draft_msg);
1143 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1144 attachments_list, images_list, priority_flags,
1145 references, in_reply_to,
1146 modest_mail_operation_send_new_mail_cb, info);
1152 ModestMailOperation *mailop;
1154 SaveToDraftstCallback callback;
1156 } FinishSaveRemoteDraftInfo;
1159 finish_save_remote_draft (ModestAccountProtocol *protocol,
1161 const gchar *account_id,
1162 TnyMsg *new_remote_msg,
1167 FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
1168 ModestMailOperationPrivate *priv = NULL;
1170 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1172 if (!priv->error && err != NULL) {
1173 /* Priority for errors in save to local stage */
1174 priv->error = g_error_copy (err);
1175 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1179 info->callback (info->mailop, info->msg, info->userdata);
1182 g_object_unref (info->msg);
1184 modest_mail_operation_notify_end (info->mailop);
1185 g_object_unref (info->mailop);
1187 g_slice_free (FinishSaveRemoteDraftInfo, info);
1192 TnyTransportAccount *transport_account;
1194 SaveToDraftstCallback callback;
1198 ModestMailOperation *mailop;
1199 } SaveToDraftsAddMsgInfo;
1202 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1207 ModestMailOperationPrivate *priv = NULL;
1208 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1209 GError *io_error = NULL;
1210 gboolean callback_called = FALSE;
1212 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1214 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1215 io_error = priv->error;
1219 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1220 g_error_free(priv->error);
1223 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1225 if ((!priv->error) && (info->draft_msg != NULL)) {
1226 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1227 TnyFolder *src_folder = tny_header_get_folder (header);
1229 g_debug ("--- REMOVE AND SYNC");
1230 /* Remove the old draft */
1231 tny_folder_remove_msg (src_folder, header, NULL);
1233 /* Synchronize to expunge and to update the msg counts */
1234 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1235 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1236 g_debug ("--- REMOVED - SYNCED");
1238 g_object_unref (G_OBJECT(header));
1239 g_object_unref (G_OBJECT(src_folder));
1243 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1245 g_error_free (io_error);
1248 } else if (io_error) {
1249 priv->error = io_error;
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1252 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1255 if (info->transport_account) {
1256 ModestProtocolType transport_protocol_type;
1257 ModestProtocol *transport_protocol;
1259 transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
1261 transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1262 transport_protocol_type);
1263 if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
1264 FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
1265 srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
1266 srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
1267 srd_info->callback = info->callback;
1268 srd_info->userdata = info->user_data;
1269 modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol),
1270 tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
1271 info->msg, info->draft_msg,
1272 finish_save_remote_draft,
1275 callback_called = TRUE;
1279 /* Call the user callback */
1280 if (!callback_called && info->callback)
1281 info->callback (info->mailop, info->msg, info->user_data);
1283 if (info->transport_account)
1284 g_object_unref (G_OBJECT(info->transport_account));
1285 if (info->draft_msg)
1286 g_object_unref (G_OBJECT (info->draft_msg));
1288 g_object_unref (G_OBJECT(info->drafts));
1290 g_object_unref (G_OBJECT (info->msg));
1292 if (!callback_called)
1293 modest_mail_operation_notify_end (info->mailop);
1295 g_object_unref(info->mailop);
1296 g_slice_free (SaveToDraftsAddMsgInfo, info);
1301 TnyTransportAccount *transport_account;
1303 SaveToDraftstCallback callback;
1308 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1312 TnyFolder *drafts = NULL;
1313 ModestMailOperationPrivate *priv = NULL;
1314 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1316 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1319 if (!(priv->error)) {
1320 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1321 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1322 "modest: failed to create a new msg\n");
1325 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1326 TNY_FOLDER_TYPE_DRAFTS);
1327 if (!drafts && !(priv->error)) {
1328 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1329 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1330 "modest: failed to create a new msg\n");
1334 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1336 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1337 cb_info->transport_account = g_object_ref(info->transport_account);
1338 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1339 cb_info->callback = info->callback;
1340 cb_info->user_data = info->user_data;
1341 cb_info->drafts = g_object_ref(drafts);
1342 cb_info->msg = g_object_ref(msg);
1343 cb_info->mailop = g_object_ref(self);
1344 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1348 /* Call the user callback */
1349 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1351 info->callback (self, msg, info->user_data);
1352 modest_mail_operation_notify_end (self);
1356 g_object_unref (G_OBJECT(drafts));
1357 if (info->draft_msg)
1358 g_object_unref (G_OBJECT (info->draft_msg));
1359 if (info->transport_account)
1360 g_object_unref (G_OBJECT(info->transport_account));
1361 g_slice_free (SaveToDraftsInfo, info);
1365 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1366 TnyTransportAccount *transport_account,
1368 const gchar *from, const gchar *to,
1369 const gchar *cc, const gchar *bcc,
1370 const gchar *subject, const gchar *plain_body,
1371 const gchar *html_body,
1372 const GList *attachments_list,
1373 const GList *images_list,
1374 TnyHeaderFlags priority_flags,
1375 const gchar *references,
1376 const gchar *in_reply_to,
1377 SaveToDraftstCallback callback,
1380 ModestMailOperationPrivate *priv = NULL;
1381 SaveToDraftsInfo *info = NULL;
1383 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1384 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1386 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1388 /* Get account and set it into mail_operation */
1389 priv->account = g_object_ref (transport_account);
1390 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1392 info = g_slice_new0 (SaveToDraftsInfo);
1393 info->transport_account = g_object_ref (transport_account);
1394 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1395 info->callback = callback;
1396 info->user_data = user_data;
1398 g_debug ("--- CREATE MESSAGE");
1399 modest_mail_operation_notify_start (self);
1400 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1401 attachments_list, images_list, priority_flags,
1402 references, in_reply_to,
1403 modest_mail_operation_save_to_drafts_cb, info);
1408 ModestMailOperation *mail_op;
1409 TnyMimePart *mime_part;
1411 GetMimePartSizeCallback callback;
1413 } GetMimePartSizeInfo;
1415 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1416 /* We use this folder observer to track the headers that have been
1417 * added to a folder */
1420 TnyList *new_headers;
1421 } InternalFolderObserver;
1424 GObjectClass parent;
1425 } InternalFolderObserverClass;
1427 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1429 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1430 internal_folder_observer,
1432 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1436 foreach_add_item (gpointer header, gpointer user_data)
1438 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1441 /* This is the method that looks for new messages in a folder */
1443 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1445 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1447 TnyFolderChangeChanged changed;
1449 changed = tny_folder_change_get_changed (change);
1451 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1454 /* Get added headers */
1455 list = tny_simple_list_new ();
1456 tny_folder_change_get_added_headers (change, list);
1458 /* Add them to the folder observer */
1459 tny_list_foreach (list, foreach_add_item,
1460 derived->new_headers);
1462 g_object_unref (G_OBJECT (list));
1467 internal_folder_observer_init (InternalFolderObserver *self)
1469 self->new_headers = tny_simple_list_new ();
1472 internal_folder_observer_finalize (GObject *object)
1474 InternalFolderObserver *self;
1476 self = (InternalFolderObserver *) object;
1477 g_object_unref (self->new_headers);
1479 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1482 tny_folder_observer_init (TnyFolderObserverIface *iface)
1484 iface->update = internal_folder_observer_update;
1487 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1489 GObjectClass *object_class;
1491 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1492 object_class = (GObjectClass*) klass;
1493 object_class->finalize = internal_folder_observer_finalize;
1497 destroy_update_account_info (UpdateAccountInfo *info)
1499 g_free (info->account_name);
1500 g_object_unref (info->folders);
1501 g_object_unref (info->mail_op);
1502 g_slice_free (UpdateAccountInfo, info);
1507 update_account_send_mail (UpdateAccountInfo *info)
1509 TnyTransportAccount *transport_account = NULL;
1510 ModestTnyAccountStore *account_store;
1512 account_store = modest_runtime_get_account_store ();
1514 /* We don't try to send messages while sending mails is blocked */
1515 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1518 /* Get the transport account */
1519 transport_account = (TnyTransportAccount *)
1520 modest_tny_account_store_get_server_account (account_store, info->account_name,
1521 TNY_ACCOUNT_TYPE_TRANSPORT);
1523 if (transport_account) {
1524 ModestTnySendQueue *send_queue;
1528 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1529 g_object_unref (transport_account);
1531 if (TNY_IS_SEND_QUEUE (send_queue)) {
1532 /* Get outbox folder */
1533 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1534 if (outbox) { /* this could fail in some cases */
1535 num_messages = tny_folder_get_all_count (outbox);
1536 g_object_unref (outbox);
1538 g_warning ("%s: could not get outbox", __FUNCTION__);
1542 if (num_messages != 0) {
1543 ModestMailOperation *mail_op;
1544 /* Reenable suspended items */
1545 mail_op = modest_mail_operation_new (NULL);
1546 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1548 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1551 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1559 update_account_get_msg_async_cb (TnyFolder *folder,
1565 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1566 ModestMailOperationPrivate *priv;
1568 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1571 if (TNY_IS_MSG (msg)) {
1572 TnyHeader *header = tny_msg_get_header (msg);
1575 ModestMailOperationState *state;
1576 state = modest_mail_operation_clone_state (msg_info->mail_op);
1577 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1578 state->bytes_done = msg_info->sum_total_bytes;
1579 state->bytes_total = msg_info->total_bytes;
1581 /* Notify the status change. Only notify about changes
1582 referred to bytes */
1583 g_signal_emit (G_OBJECT (msg_info->mail_op),
1584 signals[PROGRESS_CHANGED_SIGNAL],
1587 g_object_unref (header);
1588 g_slice_free (ModestMailOperationState, state);
1592 if (priv->done == priv->total) {
1593 TnyList *new_headers;
1594 UpdateAccountInfo *info;
1596 /* After getting all the messages send the ones in the
1598 info = (UpdateAccountInfo *) msg_info->user_data;
1599 update_account_send_mail (info);
1601 /* Check if the operation was a success */
1603 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1605 /* Call the user callback and free */
1606 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1607 update_account_notify_user_and_free (info, new_headers);
1609 /* Delete the helper */
1611 g_object_unref (msg_info->msg);
1612 g_object_unref (msg_info->more_msgs);
1613 g_object_unref (msg_info->mail_op);
1614 g_slice_free (GetMsgInfo, msg_info);
1619 update_account_notify_user_and_free (UpdateAccountInfo *info,
1620 TnyList *new_headers)
1622 /* Set the account back to not busy */
1623 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1624 info->account_name, FALSE);
1628 info->callback (info->mail_op, new_headers, info->user_data);
1630 /* Mail operation end */
1631 modest_mail_operation_notify_end (info->mail_op);
1635 g_object_unref (new_headers);
1636 destroy_update_account_info (info);
1640 inbox_refreshed_cb (TnyFolder *inbox,
1645 UpdateAccountInfo *info;
1646 ModestMailOperationPrivate *priv;
1647 TnyIterator *new_headers_iter;
1648 GPtrArray *new_headers_array = NULL;
1649 gint max_size, retrieve_limit, i;
1650 ModestAccountMgr *mgr;
1651 ModestAccountRetrieveType retrieve_type;
1652 TnyList *new_headers = NULL;
1653 gboolean headers_only;
1654 time_t time_to_store;
1656 info = (UpdateAccountInfo *) user_data;
1657 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1658 mgr = modest_runtime_get_account_mgr ();
1660 if (canceled || err) {
1661 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1663 priv->error = g_error_copy (err);
1665 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1666 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1670 tny_folder_remove_observer (inbox, info->inbox_observer);
1671 g_object_unref (info->inbox_observer);
1672 info->inbox_observer = NULL;
1674 /* Notify the user about the error and then exit */
1675 update_account_notify_user_and_free (info, NULL);
1680 /* Try to send anyway */
1684 /* Set the last updated as the current time */
1685 #ifdef MODEST_USE_LIBTIME
1687 time_get_utc (&utc_tm);
1688 time_to_store = time_mktime (&utc_tm, "GMT");
1690 time_to_store = time (NULL);
1692 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
1694 /* Get the message max size */
1695 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1696 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1698 max_size = G_MAXINT;
1700 max_size = max_size * KB;
1702 /* Create the new headers array. We need it to sort the
1703 new headers by date */
1704 new_headers_array = g_ptr_array_new ();
1705 if (info->inbox_observer) {
1706 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1707 while (!tny_iterator_is_done (new_headers_iter)) {
1708 TnyHeader *header = NULL;
1710 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1711 /* Apply per-message size limits */
1712 if (tny_header_get_message_size (header) < max_size)
1713 g_ptr_array_add (new_headers_array, g_object_ref (header));
1715 g_object_unref (header);
1716 tny_iterator_next (new_headers_iter);
1718 g_object_unref (new_headers_iter);
1720 tny_folder_remove_observer (inbox, info->inbox_observer);
1721 g_object_unref (info->inbox_observer);
1722 info->inbox_observer = NULL;
1725 if (new_headers_array->len == 0) {
1726 g_ptr_array_free (new_headers_array, FALSE);
1730 /* Get per-account message amount retrieval limit */
1731 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1732 if (retrieve_limit == 0)
1733 retrieve_limit = G_MAXINT;
1735 /* Get per-account retrieval type */
1736 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1737 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1740 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1742 /* Copy the headers to a list and free the array */
1743 new_headers = tny_simple_list_new ();
1744 for (i=0; i < new_headers_array->len; i++) {
1745 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1746 /* We want the first element to be the most recent
1747 one, that's why we reverse the list */
1748 tny_list_prepend (new_headers, G_OBJECT (header));
1750 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1751 g_ptr_array_free (new_headers_array, FALSE);
1753 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1756 GetMsgInfo *msg_info;
1759 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1761 iter = tny_list_create_iterator (new_headers);
1763 /* Create the message info */
1764 msg_info = g_slice_new0 (GetMsgInfo);
1765 msg_info->mail_op = g_object_ref (info->mail_op);
1766 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1767 msg_info->more_msgs = g_object_ref (iter);
1768 msg_info->msg = NULL;
1769 msg_info->user_data = info;
1771 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1772 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1773 TnyFolder *folder = tny_header_get_folder (header);
1775 /* Get message in an async way */
1776 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1779 g_object_unref (folder);
1780 g_object_unref (header);
1783 tny_iterator_next (iter);
1785 g_object_unref (iter);
1786 g_object_unref (new_headers);
1788 /* The mail operation will finish when the last
1789 message is retrieved */
1793 /* If we don't have to retrieve the new messages then
1795 update_account_send_mail (info);
1797 /* Check if the operation was a success */
1799 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1801 /* Call the user callback and free */
1802 update_account_notify_user_and_free (info, new_headers);
1806 inbox_refresh_status_update (GObject *obj,
1810 UpdateAccountInfo *info = NULL;
1811 ModestMailOperation *self = NULL;
1812 ModestMailOperationPrivate *priv = NULL;
1813 ModestMailOperationState *state;
1815 g_return_if_fail (user_data != NULL);
1816 g_return_if_fail (status != NULL);
1818 /* Show only the status information we want */
1819 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1822 info = (UpdateAccountInfo *) user_data;
1823 self = info->mail_op;
1824 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1826 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1828 priv->done = status->position;
1829 priv->total = status->of_total;
1831 state = modest_mail_operation_clone_state (self);
1833 /* This is not a GDK lock because we are a Tinymail callback and
1834 * Tinymail already acquires the Gdk lock */
1835 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1837 g_slice_free (ModestMailOperationState, state);
1841 recurse_folders_async_cb (TnyFolderStore *folder_store,
1847 UpdateAccountInfo *info;
1848 ModestMailOperationPrivate *priv;
1850 info = (UpdateAccountInfo *) user_data;
1851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1853 if (err || canceled) {
1854 /* If the error was previosly set by another callback
1855 don't set it again */
1857 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1859 priv->error = g_error_copy (err);
1861 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1862 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1866 /* We're not getting INBOX children if we don't want to poke all */
1867 TnyIterator *iter = tny_list_create_iterator (list);
1868 while (!tny_iterator_is_done (iter)) {
1869 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1871 /* Add to the list of all folders */
1872 tny_list_append (info->folders, (GObject *) folder);
1874 if (info->poke_all) {
1875 TnyList *folders = tny_simple_list_new ();
1876 /* Add pending call */
1877 info->pending_calls++;
1879 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1880 recurse_folders_async_cb,
1882 g_object_unref (folders);
1885 g_object_unref (G_OBJECT (folder));
1887 tny_iterator_next (iter);
1889 g_object_unref (G_OBJECT (iter));
1892 /* Remove my own pending call */
1893 info->pending_calls--;
1895 /* This means that we have all the folders */
1896 if (info->pending_calls == 0) {
1897 TnyIterator *iter_all_folders;
1898 TnyFolder *inbox = NULL;
1900 /* If there was any error do not continue */
1902 update_account_notify_user_and_free (info, NULL);
1906 iter_all_folders = tny_list_create_iterator (info->folders);
1908 /* Do a poke status over all folders */
1909 while (!tny_iterator_is_done (iter_all_folders) &&
1910 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1911 TnyFolder *folder = NULL;
1913 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1915 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1916 /* Get a reference to the INBOX */
1917 inbox = g_object_ref (folder);
1919 /* Issue a poke status over the folder */
1921 tny_folder_poke_status (folder);
1924 /* Free and go to next */
1925 g_object_unref (folder);
1926 tny_iterator_next (iter_all_folders);
1928 g_object_unref (iter_all_folders);
1930 /* Refresh the INBOX */
1932 /* Refresh the folder. Our observer receives
1933 * the new emails during folder refreshes, so
1934 * we can use observer->new_headers
1936 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1937 tny_folder_add_observer (inbox, info->inbox_observer);
1939 /* Refresh the INBOX */
1940 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1941 g_object_unref (inbox);
1943 /* We could not perform the inbox refresh but
1944 we'll try to send mails anyway */
1945 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1951 modest_mail_operation_update_account (ModestMailOperation *self,
1952 const gchar *account_name,
1954 gboolean interactive,
1955 UpdateAccountCallback callback,
1958 UpdateAccountInfo *info = NULL;
1959 ModestMailOperationPrivate *priv = NULL;
1960 ModestTnyAccountStore *account_store = NULL;
1962 ModestMailOperationState *state;
1964 /* Init mail operation */
1965 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1968 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1969 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1971 /* Get the store account */
1972 account_store = modest_runtime_get_account_store ();
1974 modest_tny_account_store_get_server_account (account_store,
1976 TNY_ACCOUNT_TYPE_STORE);
1978 /* The above function could return NULL */
1979 if (!priv->account) {
1980 /* Check if the operation was a success */
1981 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1982 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1984 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1986 /* Call the user callback */
1988 callback (self, NULL, user_data);
1990 /* Notify about operation end */
1991 modest_mail_operation_notify_end (self);
1996 /* We have once seen priv->account getting finalized during this code,
1997 * therefore adding a reference (bug #82296) */
1999 g_object_ref (priv->account);
2001 /* Create the helper object */
2002 info = g_slice_new0 (UpdateAccountInfo);
2003 info->pending_calls = 1;
2004 info->folders = tny_simple_list_new ();
2005 info->mail_op = g_object_ref (self);
2006 info->poke_all = poke_all;
2007 info->interactive = interactive;
2008 info->account_name = g_strdup (account_name);
2009 info->callback = callback;
2010 info->user_data = user_data;
2012 /* Set account busy */
2013 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2014 modest_mail_operation_notify_start (self);
2016 /* notify about the start of the operation */
2017 state = modest_mail_operation_clone_state (self);
2021 /* Start notifying progress */
2022 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2023 g_slice_free (ModestMailOperationState, state);
2025 /* Get all folders and continue in the callback */
2026 folders = tny_simple_list_new ();
2027 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2028 folders, NULL, TRUE,
2029 recurse_folders_async_cb,
2031 g_object_unref (folders);
2033 g_object_unref (priv->account);
2038 * Used to notify the queue from the main
2039 * loop. We call it inside an idle call to achieve that
2042 idle_notify_queue (gpointer data)
2044 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2046 gdk_threads_enter ();
2047 modest_mail_operation_notify_end (mail_op);
2048 gdk_threads_leave ();
2049 g_object_unref (mail_op);
2055 compare_headers_by_date (gconstpointer a,
2058 TnyHeader **header1, **header2;
2059 time_t sent1, sent2;
2061 header1 = (TnyHeader **) a;
2062 header2 = (TnyHeader **) b;
2064 sent1 = tny_header_get_date_sent (*header1);
2065 sent2 = tny_header_get_date_sent (*header2);
2067 /* We want the most recent ones (greater time_t) at the
2076 /* ******************************************************************* */
2077 /* ************************** STORE ACTIONS ************************* */
2078 /* ******************************************************************* */
2081 ModestMailOperation *mail_op;
2082 CreateFolderUserCallback callback;
2088 create_folder_cb (TnyFolderStore *parent_folder,
2090 TnyFolder *new_folder,
2094 ModestMailOperationPrivate *priv;
2095 CreateFolderInfo *info;
2097 info = (CreateFolderInfo *) user_data;
2098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2100 if (canceled || err) {
2101 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2103 priv->error = g_error_copy (err);
2105 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2106 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2109 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2112 /* The user will unref the new_folder */
2114 info->callback (info->mail_op, parent_folder,
2115 new_folder, info->user_data);
2117 /* Notify about operation end */
2118 modest_mail_operation_notify_end (info->mail_op);
2121 g_object_unref (info->mail_op);
2122 g_slice_free (CreateFolderInfo, info);
2126 modest_mail_operation_create_folder (ModestMailOperation *self,
2127 TnyFolderStore *parent,
2129 CreateFolderUserCallback callback,
2132 ModestMailOperationPrivate *priv;
2134 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2135 g_return_if_fail (name);
2137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2138 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2139 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2140 g_object_ref (parent) :
2141 modest_tny_folder_get_account (TNY_FOLDER (parent));
2143 /* Check for already existing folder */
2144 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2145 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2146 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2147 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2148 _CS("ckdg_ib_folder_already_exists"));
2152 if (TNY_IS_FOLDER (parent)) {
2153 /* Check folder rules */
2154 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2155 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2156 /* Set status failed and set an error */
2157 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2158 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2159 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2160 _("mail_in_ui_folder_create_error"));
2164 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2165 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2166 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2167 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2168 _("mail_in_ui_folder_create_error"));
2172 CreateFolderInfo *info;
2174 info = g_slice_new0 (CreateFolderInfo);
2175 info->mail_op = g_object_ref (self);
2176 info->callback = callback;
2177 info->user_data = user_data;
2179 modest_mail_operation_notify_start (self);
2181 /* Create the folder */
2182 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2185 /* Call the user callback anyway */
2187 callback (self, parent, NULL, user_data);
2188 /* Notify about operation end */
2189 modest_mail_operation_notify_end (self);
2194 modest_mail_operation_remove_folder (ModestMailOperation *self,
2196 gboolean remove_to_trash)
2198 ModestMailOperationPrivate *priv;
2199 ModestTnyFolderRules rules;
2201 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2202 g_return_if_fail (TNY_IS_FOLDER (folder));
2204 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2206 /* Check folder rules */
2207 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2208 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2209 /* Set status failed and set an error */
2210 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2211 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2212 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2213 _("mail_in_ui_folder_delete_error"));
2217 /* Get the account */
2218 priv->account = modest_tny_folder_get_account (folder);
2219 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2221 /* Delete folder or move to trash */
2222 if (remove_to_trash) {
2223 TnyFolder *trash_folder = NULL;
2224 trash_folder = modest_tny_account_get_special_folder (priv->account,
2225 TNY_FOLDER_TYPE_TRASH);
2226 /* TODO: error_handling */
2228 modest_mail_operation_notify_start (self);
2229 modest_mail_operation_xfer_folder (self, folder,
2230 TNY_FOLDER_STORE (trash_folder),
2232 g_object_unref (trash_folder);
2234 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2237 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2239 modest_mail_operation_notify_start (self);
2240 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2241 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2246 g_object_unref (parent);
2248 g_warning ("%s: could not get parent folder", __FUNCTION__);
2252 /* Notify about operation end */
2253 modest_mail_operation_notify_end (self);
2257 transfer_folder_status_cb (GObject *obj,
2261 ModestMailOperation *self;
2262 ModestMailOperationPrivate *priv;
2263 ModestMailOperationState *state;
2264 XFerFolderAsyncHelper *helper;
2266 g_return_if_fail (status != NULL);
2268 /* Show only the status information we want */
2269 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2272 helper = (XFerFolderAsyncHelper *) user_data;
2273 g_return_if_fail (helper != NULL);
2275 self = helper->mail_op;
2276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2278 priv->done = status->position;
2279 priv->total = status->of_total;
2281 state = modest_mail_operation_clone_state (self);
2283 /* This is not a GDK lock because we are a Tinymail callback
2284 * which is already GDK locked by Tinymail */
2286 /* no gdk_threads_enter (), CHECKED */
2288 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2290 /* no gdk_threads_leave (), CHECKED */
2292 g_slice_free (ModestMailOperationState, state);
2296 transfer_folder_cb (TnyFolder *folder,
2298 TnyFolderStore *into,
2299 TnyFolder *new_folder,
2303 XFerFolderAsyncHelper *helper;
2304 ModestMailOperation *self = NULL;
2305 ModestMailOperationPrivate *priv = NULL;
2307 helper = (XFerFolderAsyncHelper *) user_data;
2308 g_return_if_fail (helper != NULL);
2310 self = helper->mail_op;
2311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2314 priv->error = g_error_copy (err);
2316 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2317 } else if (cancelled) {
2318 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2320 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2321 _("Transference of %s was cancelled."),
2322 tny_folder_get_name (folder));
2325 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2328 /* Update state of new folder */
2330 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2331 tny_folder_poke_status (new_folder);
2334 /* Notify about operation end */
2335 modest_mail_operation_notify_end (self);
2337 /* If user defined callback function was defined, call it */
2338 if (helper->user_callback) {
2340 /* This is not a GDK lock because we are a Tinymail callback
2341 * which is already GDK locked by Tinymail */
2343 /* no gdk_threads_enter (), CHECKED */
2344 helper->user_callback (self, new_folder, helper->user_data);
2345 /* no gdk_threads_leave () , CHECKED */
2349 g_object_unref (helper->mail_op);
2350 g_slice_free (XFerFolderAsyncHelper, helper);
2355 * This function checks if the new name is a valid name for our local
2356 * folders account. The new name could not be the same than then name
2357 * of any of the mandatory local folders
2359 * We can not rely on tinymail because tinymail does not check the
2360 * name of the virtual folders that the account could have in the case
2361 * that we're doing a rename (because it directly calls Camel which
2362 * knows nothing about our virtual folders).
2364 * In the case of an actual copy/move (i.e. move/copy a folder between
2365 * accounts) tinymail uses the tny_folder_store_create_account which
2366 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2367 * checks the new name of the folder, so this call in that case
2368 * wouldn't be needed. *But* NOTE that if tinymail changes its
2369 * implementation (if folder transfers within the same account is no
2370 * longer implemented as a rename) this call will allow Modest to work
2373 * If the new name is not valid, this function will set the status to
2374 * failed and will set also an error in the mail operation
2377 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2378 TnyFolderStore *into,
2379 const gchar *new_name)
2381 if (TNY_IS_ACCOUNT (into) &&
2382 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2383 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2385 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2386 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2387 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2388 _CS("ckdg_ib_folder_already_exists"));
2395 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2397 TnyFolderStore *parent,
2398 gboolean delete_original,
2399 XferFolderAsyncUserCallback user_callback,
2402 ModestMailOperationPrivate *priv = NULL;
2403 ModestTnyFolderRules parent_rules = 0, rules;
2404 XFerFolderAsyncHelper *helper = NULL;
2405 const gchar *folder_name = NULL;
2406 const gchar *error_msg;
2408 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2409 g_return_if_fail (TNY_IS_FOLDER (folder));
2410 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2413 folder_name = tny_folder_get_name (folder);
2415 /* Set the error msg */
2416 error_msg = _("mail_in_ui_folder_move_target_error");
2418 /* Get account and set it into mail_operation */
2419 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2420 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2421 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2423 /* Get folder rules */
2424 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2425 if (TNY_IS_FOLDER (parent))
2426 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2428 /* Apply operation constraints */
2429 if ((gpointer) parent == (gpointer) folder ||
2430 (!TNY_IS_FOLDER_STORE (parent)) ||
2431 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2434 } else if (TNY_IS_FOLDER (parent) &&
2435 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2439 } else if (TNY_IS_FOLDER (parent) &&
2440 TNY_IS_FOLDER_STORE (folder) &&
2441 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2442 TNY_FOLDER_STORE (folder))) {
2443 /* Do not move a parent into a child */
2445 } else if (TNY_IS_FOLDER_STORE (parent) &&
2446 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2447 /* Check that the new folder name is not used by any
2450 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2451 /* Check that the new folder name is not used by any
2452 special local folder */
2455 /* Create the helper */
2456 helper = g_slice_new0 (XFerFolderAsyncHelper);
2457 helper->mail_op = g_object_ref (self);
2458 helper->user_callback = user_callback;
2459 helper->user_data = user_data;
2461 /* Move/Copy folder */
2462 modest_mail_operation_notify_start (self);
2463 tny_folder_copy_async (folder,
2465 tny_folder_get_name (folder),
2468 transfer_folder_status_cb,
2474 /* Set status failed and set an error */
2475 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2476 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2477 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2480 /* Call the user callback if exists */
2482 user_callback (self, NULL, user_data);
2484 /* Notify the queue */
2485 modest_mail_operation_notify_end (self);
2489 modest_mail_operation_rename_folder (ModestMailOperation *self,
2492 XferFolderAsyncUserCallback user_callback,
2495 ModestMailOperationPrivate *priv;
2496 ModestTnyFolderRules rules;
2497 XFerFolderAsyncHelper *helper;
2499 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2500 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2501 g_return_if_fail (name);
2503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2505 /* Get account and set it into mail_operation */
2506 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2507 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2509 /* Check folder rules */
2510 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2511 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2513 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2516 TnyFolderStore *into;
2518 into = tny_folder_get_folder_store (folder);
2520 /* Check that the new folder name is not used by any
2521 special local folder */
2522 if (new_name_valid_if_local_account (priv, into, name)) {
2523 /* Create the helper */
2524 helper = g_slice_new0 (XFerFolderAsyncHelper);
2525 helper->mail_op = g_object_ref(self);
2526 helper->user_callback = user_callback;
2527 helper->user_data = user_data;
2529 /* Rename. Camel handles folder subscription/unsubscription */
2530 modest_mail_operation_notify_start (self);
2531 tny_folder_copy_async (folder, into, name, TRUE,
2533 transfer_folder_status_cb,
2535 g_object_unref (into);
2537 g_object_unref (into);
2544 /* Set status failed and set an error */
2545 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2546 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2547 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2548 _("FIXME: unable to rename"));
2551 user_callback (self, NULL, user_data);
2553 /* Notify about operation end */
2554 modest_mail_operation_notify_end (self);
2557 /* ******************************************************************* */
2558 /* ************************** MSG ACTIONS ************************* */
2559 /* ******************************************************************* */
2562 modest_mail_operation_find_msg (ModestMailOperation *self,
2564 const gchar *msg_uid,
2565 gboolean progress_feedback,
2566 GetMsgAsyncUserCallback user_callback,
2569 GetMsgInfo *helper = NULL;
2570 ModestMailOperationPrivate *priv;
2572 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2573 g_return_if_fail (msg_uid != NULL);
2575 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2576 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2580 /* Check memory low */
2581 if (_check_memory_low (self)) {
2583 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2584 modest_mail_operation_notify_end (self);
2588 /* Get account and set it into mail_operation */
2589 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2591 /* Check for cached messages */
2592 if (progress_feedback) {
2593 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2595 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2598 /* Create the helper */
2599 helper = g_slice_new0 (GetMsgInfo);
2600 helper->header = NULL;
2601 helper->mail_op = g_object_ref (self);
2602 helper->user_callback = user_callback;
2603 helper->user_data = user_data;
2604 helper->destroy_notify = NULL;
2605 helper->last_total_bytes = 0;
2606 helper->sum_total_bytes = 0;
2607 helper->total_bytes = 0;
2608 helper->more_msgs = NULL;
2609 helper->get_parts = NULL;
2612 modest_mail_operation_notify_start (self);
2614 /* notify about the start of the operation */
2615 ModestMailOperationState *state;
2616 state = modest_mail_operation_clone_state (self);
2619 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2621 g_slice_free (ModestMailOperationState, state);
2623 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2627 modest_mail_operation_get_msg (ModestMailOperation *self,
2629 gboolean progress_feedback,
2630 GetMsgAsyncUserCallback user_callback,
2633 GetMsgInfo *helper = NULL;
2635 ModestMailOperationPrivate *priv;
2637 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2638 g_return_if_fail (TNY_IS_HEADER (header));
2640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2641 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2645 /* Check memory low */
2646 if (_check_memory_low (self)) {
2648 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2649 modest_mail_operation_notify_end (self);
2653 /* Get account and set it into mail_operation */
2654 folder = tny_header_get_folder (header);
2655 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2657 /* Check for cached messages */
2658 if (progress_feedback) {
2659 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2660 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2662 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2664 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2667 /* Create the helper */
2668 helper = g_slice_new0 (GetMsgInfo);
2669 helper->header = g_object_ref (header);
2670 helper->mail_op = g_object_ref (self);
2671 helper->user_callback = user_callback;
2672 helper->user_data = user_data;
2673 helper->destroy_notify = NULL;
2674 helper->last_total_bytes = 0;
2675 helper->sum_total_bytes = 0;
2676 helper->total_bytes = tny_header_get_message_size (header);
2677 helper->more_msgs = NULL;
2678 helper->get_parts = NULL;
2681 modest_mail_operation_notify_start (self);
2683 /* notify about the start of the operation */
2684 ModestMailOperationState *state;
2685 state = modest_mail_operation_clone_state (self);
2688 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2690 g_slice_free (ModestMailOperationState, state);
2692 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2694 g_object_unref (G_OBJECT (folder));
2698 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2701 gboolean progress_feedback,
2702 GetMsgAsyncUserCallback user_callback,
2705 GetMsgInfo *helper = NULL;
2707 ModestMailOperationPrivate *priv;
2709 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2710 g_return_if_fail (TNY_IS_HEADER (header));
2712 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2713 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2717 /* Check memory low */
2718 if (_check_memory_low (self)) {
2720 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2721 modest_mail_operation_notify_end (self);
2725 /* Get account and set it into mail_operation */
2726 folder = tny_header_get_folder (header);
2727 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2728 const gchar *acc_name;
2729 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2730 priv->account = modest_tny_account_store_get_server_account
2731 (modest_runtime_get_account_store (),
2733 TNY_ACCOUNT_TYPE_STORE);
2734 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2735 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2737 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2740 /* Check for cached messages */
2741 if (progress_feedback) {
2742 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2743 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2745 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2747 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2750 /* Create the helper */
2751 helper = g_slice_new0 (GetMsgInfo);
2752 helper->header = g_object_ref (header);
2753 helper->mail_op = g_object_ref (self);
2754 helper->user_callback = user_callback;
2755 helper->user_data = user_data;
2756 helper->destroy_notify = NULL;
2757 helper->last_total_bytes = 0;
2758 helper->sum_total_bytes = 0;
2759 helper->total_bytes = tny_header_get_message_size (header);
2760 helper->more_msgs = NULL;
2761 helper->get_parts = tny_list_create_iterator (parts);
2764 modest_mail_operation_notify_start (self);
2766 /* notify about the start of the operation */
2767 ModestMailOperationState *state;
2768 state = modest_mail_operation_clone_state (self);
2771 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2773 g_slice_free (ModestMailOperationState, state);
2775 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2777 g_object_unref (G_OBJECT (folder));
2781 get_msg_status_cb (GObject *obj,
2785 GetMsgInfo *helper = NULL;
2787 g_return_if_fail (status != NULL);
2789 /* Show only the status information we want */
2790 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2793 helper = (GetMsgInfo *) user_data;
2794 g_return_if_fail (helper != NULL);
2796 /* Notify progress */
2797 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2798 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2802 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2805 TnyFolder *folder = NULL;
2807 helper = (GetMsgInfo *) user_data;
2809 if (helper->header) {
2810 folder = tny_header_get_folder (helper->header);
2813 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2815 if (folder) g_object_unref (folder);
2819 get_msg_async_cb (TnyFolder *folder,
2825 GetMsgInfo *info = NULL;
2826 ModestMailOperationPrivate *priv = NULL;
2829 info = (GetMsgInfo *) user_data;
2831 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2834 if (info->more_msgs) {
2835 tny_iterator_next (info->more_msgs);
2836 finished = (tny_iterator_is_done (info->more_msgs));
2837 } else if (info->get_parts) {
2838 tny_iterator_next (info->get_parts);
2839 finished = (tny_iterator_is_done (info->get_parts));
2841 finished = (priv->done == priv->total) ? TRUE : FALSE;
2844 /* If canceled by the user, ignore the error given by Tinymail */
2848 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2850 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2851 priv->error = g_error_copy ((const GError *) err);
2853 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2855 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2856 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2857 "%s", err->message);
2859 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2860 /* Set the success status before calling the user callback */
2861 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2864 if (info->header == NULL && msg)
2865 info->header = tny_msg_get_header (msg);
2867 /* Call the user callback */
2868 if (info->user_callback && (finished || (info->get_parts == NULL)))
2869 info->user_callback (info->mail_op, info->header, canceled,
2870 msg, err, info->user_data);
2872 /* Notify about operation end if this is the last callback */
2874 /* Free user data */
2875 if (info->destroy_notify)
2876 info->destroy_notify (info->user_data);
2878 /* Notify about operation end */
2879 modest_mail_operation_notify_end (info->mail_op);
2883 g_object_unref (info->msg);
2884 if (info->more_msgs)
2885 g_object_unref (info->more_msgs);
2887 g_object_unref (info->header);
2888 g_object_unref (info->mail_op);
2889 g_slice_free (GetMsgInfo, info);
2890 } else if (info->get_parts) {
2891 CamelStream *null_stream;
2892 TnyStream *tny_null_stream;
2895 if (info->msg == NULL && msg != NULL)
2896 info->msg = g_object_ref (msg);
2898 null_stream = camel_stream_null_new ();
2899 tny_null_stream = tny_camel_stream_new (null_stream);
2901 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
2902 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
2903 get_msg_async_get_part_cb,
2906 g_object_unref (tny_null_stream);
2907 g_object_unref (part);
2909 } else if (info->more_msgs) {
2910 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2911 TnyFolder *folder = tny_header_get_folder (header);
2913 g_object_unref (info->header);
2914 info->header = g_object_ref (header);
2916 /* Retrieve the next message */
2917 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2919 g_object_unref (header);
2920 g_object_unref (folder);
2922 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2927 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2928 TnyList *header_list,
2929 GetMsgAsyncUserCallback user_callback,
2931 GDestroyNotify notify)
2933 ModestMailOperationPrivate *priv = NULL;
2935 TnyIterator *iter = NULL;
2936 gboolean has_uncached_messages;
2938 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2940 /* Init mail operation */
2941 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2942 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2944 priv->total = tny_list_get_length(header_list);
2946 /* Check memory low */
2947 if (_check_memory_low (self)) {
2948 if (user_callback) {
2949 TnyHeader *header = NULL;
2952 if (tny_list_get_length (header_list) > 0) {
2953 iter = tny_list_create_iterator (header_list);
2954 header = (TnyHeader *) tny_iterator_get_current (iter);
2955 g_object_unref (iter);
2957 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2959 g_object_unref (header);
2963 /* Notify about operation end */
2964 modest_mail_operation_notify_end (self);
2968 /* Check uncached messages */
2969 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2970 !has_uncached_messages && !tny_iterator_is_done (iter);
2971 tny_iterator_next (iter)) {
2974 header = (TnyHeader *) tny_iterator_get_current (iter);
2975 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2976 has_uncached_messages = TRUE;
2977 g_object_unref (header);
2979 g_object_unref (iter);
2980 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2982 /* Get account and set it into mail_operation */
2983 if (tny_list_get_length (header_list) >= 1) {
2984 TnyIterator *iterator = tny_list_create_iterator (header_list);
2985 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2987 TnyFolder *folder = tny_header_get_folder (header);
2989 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2990 g_object_unref (folder);
2992 g_object_unref (header);
2994 g_object_unref (iterator);
2997 msg_list_size = compute_message_list_size (header_list, 0);
2999 modest_mail_operation_notify_start (self);
3000 iter = tny_list_create_iterator (header_list);
3001 if (!tny_iterator_is_done (iter)) {
3002 /* notify about the start of the operation */
3003 ModestMailOperationState *state;
3004 state = modest_mail_operation_clone_state (self);
3007 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3010 GetMsgInfo *msg_info = NULL;
3011 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3012 TnyFolder *folder = tny_header_get_folder (header);
3014 /* Create the message info */
3015 msg_info = g_slice_new0 (GetMsgInfo);
3016 msg_info->mail_op = g_object_ref (self);
3017 msg_info->header = g_object_ref (header);
3018 msg_info->more_msgs = g_object_ref (iter);
3019 msg_info->user_callback = user_callback;
3020 msg_info->user_data = user_data;
3021 msg_info->destroy_notify = notify;
3022 msg_info->last_total_bytes = 0;
3023 msg_info->sum_total_bytes = 0;
3024 msg_info->total_bytes = msg_list_size;
3025 msg_info->msg = NULL;
3027 /* The callback will call it per each header */
3028 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3030 /* Free and go on */
3031 g_object_unref (header);
3032 g_object_unref (folder);
3033 g_slice_free (ModestMailOperationState, state);
3035 g_object_unref (iter);
3040 remove_msgs_async_cb (TnyFolder *folder,
3046 const gchar *account_name;
3047 TnyAccount *account;
3048 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3049 ModestMailOperation *self;
3050 ModestMailOperationPrivate *priv;
3051 ModestProtocolRegistry *protocol_registry;
3052 SyncFolderHelper *helper;
3054 self = (ModestMailOperation *) user_data;
3055 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3056 protocol_registry = modest_runtime_get_protocol_registry ();
3058 if (canceled || err) {
3059 /* If canceled by the user, ignore the error given by Tinymail */
3061 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3063 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3064 priv->error = g_error_copy ((const GError *) err);
3065 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3068 modest_mail_operation_notify_end (self);
3069 g_object_unref (self);
3073 account = modest_tny_folder_get_account (folder);
3074 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3075 account_proto = modest_tny_account_get_protocol_type (account);
3076 g_object_unref (account);
3078 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3079 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3089 helper = g_slice_new0 (SyncFolderHelper);
3090 helper->mail_op = g_object_ref (self);
3091 helper->user_callback = NULL;
3092 helper->user_data = NULL;
3095 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3097 /* Remove the extra reference */
3098 g_object_unref (self);
3102 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3104 gboolean remove_to_trash /*ignored*/)
3106 TnyFolder *folder = NULL;
3107 ModestMailOperationPrivate *priv;
3108 TnyIterator *iter = NULL;
3109 TnyHeader *header = NULL;
3110 TnyList *remove_headers = NULL;
3111 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3112 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3114 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3115 g_return_if_fail (TNY_IS_LIST (headers));
3117 if (remove_to_trash)
3118 g_warning ("remove to trash is not implemented");
3120 if (tny_list_get_length(headers) == 0) {
3121 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3122 goto cleanup; /* nothing to do */
3125 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3127 /* Get folder from first header and sync it */
3128 iter = tny_list_create_iterator (headers);
3129 header = TNY_HEADER (tny_iterator_get_current (iter));
3130 g_object_unref (iter);
3132 folder = tny_header_get_folder (header);
3133 if (!TNY_IS_FOLDER(folder)) {
3134 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3138 /* Use the merged folder if we're removing messages from outbox */
3139 if (modest_tny_folder_is_local_folder (folder)) {
3140 ModestTnyLocalFoldersAccount *local_account;
3142 local_account = (ModestTnyLocalFoldersAccount *)
3143 modest_tny_account_store_get_local_folders_account (accstore);
3144 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3145 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3146 g_object_unref (folder);
3147 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3149 g_object_unref (local_account);
3152 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3153 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3155 while (!tny_iterator_is_done (headers_iter)) {
3156 TnyTransportAccount *traccount = NULL;
3157 TnyHeader *hdr = NULL;
3159 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3160 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3163 ModestTnySendQueueStatus status;
3164 ModestTnySendQueue *send_queue;
3166 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3167 if (TNY_IS_SEND_QUEUE (send_queue)) {
3170 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3171 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3172 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3173 if (G_UNLIKELY (remove_headers == NULL))
3174 remove_headers = tny_simple_list_new ();
3175 tny_list_append(remove_headers, G_OBJECT(hdr));
3179 g_object_unref(traccount);
3181 g_object_unref(hdr);
3182 tny_iterator_next (headers_iter);
3184 g_object_unref(headers_iter);
3187 /* Get account and set it into mail_operation */
3188 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3189 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3190 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3192 if (!remove_headers)
3193 remove_headers = g_object_ref (headers);
3195 /* remove message from folder */
3196 modest_mail_operation_notify_start (self);
3197 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3198 NULL, g_object_ref (self));
3202 g_object_unref (remove_headers);
3204 g_object_unref (header);
3206 g_object_unref (folder);
3210 notify_progress_of_multiple_messages (ModestMailOperation *self,
3212 gint *last_total_bytes,
3213 gint *sum_total_bytes,
3215 gboolean increment_done)
3217 ModestMailOperationPrivate *priv;
3218 ModestMailOperationState *state;
3219 gboolean is_num_bytes = FALSE;
3221 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3223 /* We know that tinymail sends us information about
3224 * transferred bytes with this particular message
3226 if (status->message)
3227 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3229 state = modest_mail_operation_clone_state (self);
3230 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3231 /* We know that we're in a different message when the
3232 total number of bytes to transfer is different. Of
3233 course it could fail if we're transferring messages
3234 of the same size, but this is a workarround */
3235 if (status->of_total != *last_total_bytes) {
3236 /* We need to increment the done when there is
3237 no information about each individual
3238 message, we need to do this in message
3239 transfers, and we don't do it for getting
3243 *sum_total_bytes += *last_total_bytes;
3244 *last_total_bytes = status->of_total;
3246 state->bytes_done += status->position + *sum_total_bytes;
3247 state->bytes_total = total_bytes;
3249 /* Notify the status change. Only notify about changes
3250 referred to bytes */
3251 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3255 g_slice_free (ModestMailOperationState, state);
3259 transfer_msgs_status_cb (GObject *obj,
3263 XFerMsgsAsyncHelper *helper;
3265 g_return_if_fail (status != NULL);
3267 /* Show only the status information we want */
3268 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3271 helper = (XFerMsgsAsyncHelper *) user_data;
3272 g_return_if_fail (helper != NULL);
3274 /* Notify progress */
3275 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3276 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3280 transfer_msgs_sync_folder_cb (TnyFolder *self,
3285 XFerMsgsAsyncHelper *helper;
3286 /* We don't care here about the results of the
3288 helper = (XFerMsgsAsyncHelper *) user_data;
3290 /* Notify about operation end */
3291 modest_mail_operation_notify_end (helper->mail_op);
3293 /* If user defined callback function was defined, call it */
3294 if (helper->user_callback)
3295 helper->user_callback (helper->mail_op, helper->user_data);
3298 if (helper->more_msgs)
3299 g_object_unref (helper->more_msgs);
3300 if (helper->headers)
3301 g_object_unref (helper->headers);
3302 if (helper->dest_folder)
3303 g_object_unref (helper->dest_folder);
3304 if (helper->mail_op)
3305 g_object_unref (helper->mail_op);
3306 g_slice_free (XFerMsgsAsyncHelper, helper);
3310 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3312 XFerMsgsAsyncHelper *helper;
3313 ModestMailOperation *self;
3314 ModestMailOperationPrivate *priv;
3315 gboolean finished = TRUE;
3317 helper = (XFerMsgsAsyncHelper *) user_data;
3318 self = helper->mail_op;
3320 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3323 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3325 priv->error = g_error_copy (err);
3327 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3328 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3329 if (helper->more_msgs) {
3330 /* We'll transfer the next message in the list */
3331 tny_iterator_next (helper->more_msgs);
3332 if (!tny_iterator_is_done (helper->more_msgs)) {
3333 GObject *next_header;
3334 g_object_unref (helper->headers);
3335 helper->headers = tny_simple_list_new ();
3336 next_header = tny_iterator_get_current (helper->more_msgs);
3337 tny_list_append (helper->headers, next_header);
3338 g_object_unref (next_header);
3344 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3349 /* Synchronize the source folder contents. This should
3350 be done by tinymail but the camel_folder_sync it's
3351 actually disabled in transfer_msgs_thread_clean
3352 because it's supposed to cause hangs */
3353 tny_folder_sync_async (folder, helper->delete,
3354 transfer_msgs_sync_folder_cb,
3357 /* Transfer more messages */
3358 tny_folder_transfer_msgs_async (folder,
3360 helper->dest_folder,
3363 transfer_msgs_status_cb,
3368 /* Computes the size of the messages the headers in the list belongs
3369 to. If num_elements is different from 0 then it only takes into
3370 account the first num_elements for the calculation */
3372 compute_message_list_size (TnyList *headers,
3376 guint size = 0, element = 0;
3378 /* If num_elements is not valid then take all into account */
3379 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3380 num_elements = tny_list_get_length (headers);
3382 iter = tny_list_create_iterator (headers);
3383 while (!tny_iterator_is_done (iter) && element < num_elements) {
3384 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3385 size += tny_header_get_message_size (header);
3386 g_object_unref (header);
3387 tny_iterator_next (iter);
3390 g_object_unref (iter);
3396 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3399 gboolean delete_original,
3400 XferMsgsAsyncUserCallback user_callback,
3403 ModestMailOperationPrivate *priv = NULL;
3404 TnyIterator *iter = NULL;
3405 TnyFolder *src_folder = NULL;
3406 XFerMsgsAsyncHelper *helper = NULL;
3407 TnyHeader *header = NULL;
3408 ModestTnyFolderRules rules = 0;
3409 TnyAccount *dst_account = NULL;
3410 gboolean leave_on_server;
3411 ModestMailOperationState *state;
3412 ModestProtocolRegistry *protocol_registry;
3413 ModestProtocolType account_protocol;
3415 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3416 g_return_if_fail (headers && TNY_IS_LIST (headers));
3417 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3419 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3420 protocol_registry = modest_runtime_get_protocol_registry ();
3422 priv->total = tny_list_get_length (headers);
3424 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3425 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3427 /* Apply folder rules */
3428 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3429 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3430 /* Set status failed and set an error */
3431 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3432 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3433 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3434 _CS("ckct_ib_unable_to_paste_here"));
3435 /* Notify the queue */
3436 modest_mail_operation_notify_end (self);
3440 /* Get source folder */
3441 iter = tny_list_create_iterator (headers);
3442 header = TNY_HEADER (tny_iterator_get_current (iter));
3444 src_folder = tny_header_get_folder (header);
3445 g_object_unref (header);
3447 g_object_unref (iter);
3449 if (src_folder == NULL) {
3450 /* Notify the queue */
3451 modest_mail_operation_notify_end (self);
3453 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3458 /* Check folder source and destination */
3459 if (src_folder == folder) {
3460 /* Set status failed and set an error */
3461 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3462 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3463 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3464 _("mail_in_ui_folder_copy_target_error"));
3466 /* Notify the queue */
3467 modest_mail_operation_notify_end (self);
3470 g_object_unref (src_folder);
3474 /* Create the helper */
3475 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3476 helper->mail_op = g_object_ref(self);
3477 helper->dest_folder = g_object_ref(folder);
3478 helper->user_callback = user_callback;
3479 helper->user_data = user_data;
3480 helper->last_total_bytes = 0;
3481 helper->sum_total_bytes = 0;
3482 helper->total_bytes = compute_message_list_size (headers, 0);
3484 /* Get account and set it into mail_operation */
3485 priv->account = modest_tny_folder_get_account (src_folder);
3486 dst_account = modest_tny_folder_get_account (folder);
3488 if (priv->account == dst_account) {
3489 /* Transfer all messages at once using the fast
3490 * method. Note that depending on the server this
3491 * might not be that fast, and might not be
3492 * user-cancellable either */
3493 helper->headers = g_object_ref (headers);
3494 helper->more_msgs = NULL;
3496 /* Transfer messages one by one so the user can cancel
3499 helper->headers = tny_simple_list_new ();
3500 helper->more_msgs = tny_list_create_iterator (headers);
3501 hdr = tny_iterator_get_current (helper->more_msgs);
3502 tny_list_append (helper->headers, hdr);
3503 g_object_unref (hdr);
3506 /* If leave_on_server is set to TRUE then don't use
3507 delete_original, we always pass FALSE. This is because
3508 otherwise tinymail will try to sync the source folder and
3509 this could cause an error if we're offline while
3510 transferring an already downloaded message from a POP
3512 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3513 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3514 const gchar *account_name;
3516 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3517 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3520 leave_on_server = FALSE;
3523 /* Do not delete messages if leave on server is TRUE */
3524 helper->delete = (leave_on_server) ? FALSE : delete_original;
3526 modest_mail_operation_notify_start (self);
3528 /* Start notifying progress */
3529 state = modest_mail_operation_clone_state (self);
3532 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3533 g_slice_free (ModestMailOperationState, state);
3535 tny_folder_transfer_msgs_async (src_folder,
3540 transfer_msgs_status_cb,
3542 g_object_unref (src_folder);
3543 g_object_unref (dst_account);
3548 on_refresh_folder (TnyFolder *folder,
3553 RefreshAsyncHelper *helper = NULL;
3554 ModestMailOperation *self = NULL;
3555 ModestMailOperationPrivate *priv = NULL;
3557 helper = (RefreshAsyncHelper *) user_data;
3558 self = helper->mail_op;
3559 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3561 g_return_if_fail(priv!=NULL);
3564 priv->error = g_error_copy (error);
3565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3570 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3571 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3572 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3573 _("Error trying to refresh the contents of %s"),
3574 tny_folder_get_name (folder));
3578 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3581 /* Call user defined callback, if it exists */
3582 if (helper->user_callback) {
3584 /* This is not a GDK lock because we are a Tinymail callback and
3585 * Tinymail already acquires the Gdk lock */
3586 helper->user_callback (self, folder, helper->user_data);
3590 g_slice_free (RefreshAsyncHelper, helper);
3592 /* Notify about operation end */
3593 modest_mail_operation_notify_end (self);
3594 g_object_unref(self);
3598 on_refresh_folder_status_update (GObject *obj,
3602 RefreshAsyncHelper *helper = NULL;
3603 ModestMailOperation *self = NULL;
3604 ModestMailOperationPrivate *priv = NULL;
3605 ModestMailOperationState *state;
3607 g_return_if_fail (user_data != NULL);
3608 g_return_if_fail (status != NULL);
3610 /* Show only the status information we want */
3611 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3614 helper = (RefreshAsyncHelper *) user_data;
3615 self = helper->mail_op;
3616 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3618 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3620 priv->done = status->position;
3621 priv->total = status->of_total;
3623 state = modest_mail_operation_clone_state (self);
3625 /* This is not a GDK lock because we are a Tinymail callback and
3626 * Tinymail already acquires the Gdk lock */
3627 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3629 g_slice_free (ModestMailOperationState, state);
3633 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3635 RefreshAsyncUserCallback user_callback,
3638 ModestMailOperationPrivate *priv = NULL;
3639 RefreshAsyncHelper *helper = NULL;
3641 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3643 /* Check memory low */
3644 if (_check_memory_low (self)) {
3646 user_callback (self, folder, user_data);
3647 /* Notify about operation end */
3648 modest_mail_operation_notify_end (self);
3652 /* Get account and set it into mail_operation */
3653 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3654 priv->account = modest_tny_folder_get_account (folder);
3655 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3657 /* Create the helper */
3658 helper = g_slice_new0 (RefreshAsyncHelper);
3659 helper->mail_op = g_object_ref(self);
3660 helper->user_callback = user_callback;
3661 helper->user_data = user_data;
3663 modest_mail_operation_notify_start (self);
3665 /* notify that the operation was started */
3666 ModestMailOperationState *state;
3667 state = modest_mail_operation_clone_state (self);
3670 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3672 g_slice_free (ModestMailOperationState, state);
3674 tny_folder_refresh_async (folder,
3676 on_refresh_folder_status_update,
3681 run_queue_notify_and_destroy (RunQueueHelper *helper,
3682 ModestMailOperationStatus status)
3684 ModestMailOperationPrivate *priv;
3687 if (helper->error_handler &&
3688 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3689 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3690 if (helper->start_handler &&
3691 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3692 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3693 if (helper->stop_handler &&
3694 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3695 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3698 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3699 priv->status = status;
3702 modest_mail_operation_notify_end (helper->self);
3705 g_object_unref (helper->queue);
3706 g_object_unref (helper->self);
3707 g_slice_free (RunQueueHelper, helper);
3711 run_queue_stop (ModestTnySendQueue *queue,
3714 RunQueueHelper *helper;
3716 g_debug ("%s sending queue stopped", __FUNCTION__);
3718 helper = (RunQueueHelper *) user_data;
3719 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3723 modest_mail_operation_run_queue (ModestMailOperation *self,
3724 ModestTnySendQueue *queue)
3726 ModestMailOperationPrivate *priv;
3727 RunQueueHelper *helper;
3729 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3730 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3731 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3733 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3734 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3735 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3737 /* Create the helper */
3738 helper = g_slice_new0 (RunQueueHelper);
3739 helper->queue = g_object_ref (queue);
3740 helper->self = g_object_ref (self);
3741 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3742 G_CALLBACK (run_queue_stop),
3745 /* Notify operation has started */
3746 modest_mail_operation_notify_start (self);
3747 g_debug ("%s, run queue started", __FUNCTION__);
3751 queue_wakeup_callback (ModestTnySendQueue *queue,
3756 ModestMailOperation *mail_op;
3757 ModestMailOperationPrivate *priv;
3759 mail_op = (ModestMailOperation *) userdata;
3760 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3762 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3763 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3766 modest_mail_operation_notify_end (mail_op);
3767 g_object_unref (mail_op);
3771 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3772 ModestTnySendQueue *queue)
3774 ModestMailOperationPrivate *priv;
3776 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3777 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3778 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3780 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3781 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3782 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3784 g_object_ref (self);
3786 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3787 modest_mail_operation_notify_start (self);
3791 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3793 ModestMailOperation *self = (ModestMailOperation *) userdata;
3794 ModestMailOperationPrivate *priv;
3796 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3797 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3798 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3800 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3802 modest_mail_operation_notify_end (self);
3803 g_object_unref (self);
3807 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3809 ModestMailOperationPrivate *priv;
3811 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3812 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3815 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3817 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3818 priv->account = NULL;
3819 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3821 modest_mail_operation_notify_start (self);
3822 g_object_ref (self);
3823 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3827 sync_folder_finish_callback (TnyFolder *self,
3833 ModestMailOperationPrivate *priv;
3834 SyncFolderHelper *helper;
3836 helper = (SyncFolderHelper *) user_data;
3837 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3839 /* If canceled by the user, ignore the error given by Tinymail */
3841 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3843 /* If the operation was a sync then the status is
3844 failed, but if it's part of another operation then
3845 just set it as finished with errors */
3846 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3847 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3849 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3850 priv->error = g_error_copy ((const GError *) err);
3851 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3853 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3857 if (helper->user_callback)
3858 helper->user_callback (helper->mail_op, self, helper->user_data);
3860 modest_mail_operation_notify_end (helper->mail_op);
3863 g_object_unref (helper->mail_op);
3864 g_slice_free (SyncFolderHelper, helper);
3868 modest_mail_operation_sync_folder (ModestMailOperation *self,
3871 SyncFolderCallback callback,
3874 ModestMailOperationPrivate *priv;
3875 SyncFolderHelper *helper;
3877 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3878 g_return_if_fail (TNY_IS_FOLDER (folder));
3879 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3881 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3882 priv->account = modest_tny_folder_get_account (folder);
3883 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3886 helper = g_slice_new0 (SyncFolderHelper);
3887 helper->mail_op = g_object_ref (self);
3888 helper->user_callback = callback;
3889 helper->user_data = user_data;
3891 modest_mail_operation_notify_start (self);
3892 tny_folder_sync_async (folder, expunge,
3893 (TnyFolderCallback) sync_folder_finish_callback,
3898 modest_mail_operation_notify_start (ModestMailOperation *self)
3900 ModestMailOperationPrivate *priv = NULL;
3902 g_return_if_fail (self);
3904 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3906 /* Ensure that all the fields are filled correctly */
3907 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3909 /* Notify the observers about the mail operation. We do not
3910 wrapp this emission because we assume that this function is
3911 always called from within the main lock */
3912 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3917 * It's used by the mail operation queue to notify the observers
3918 * attached to that signal that the operation finished. We need to use
3919 * that because tinymail does not give us the progress of a given
3920 * operation when it finishes (it directly calls the operation
3924 modest_mail_operation_notify_end (ModestMailOperation *self)
3926 ModestMailOperationPrivate *priv = NULL;
3928 g_return_if_fail (self);
3930 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3932 /* Notify the observers about the mail operation end. We do
3933 not wrapp this emission because we assume that this
3934 function is always called from within the main lock */
3935 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3937 /* Remove the error user data */
3938 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3939 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3943 modest_mail_operation_get_account (ModestMailOperation *self)
3945 ModestMailOperationPrivate *priv = NULL;
3947 g_return_val_if_fail (self, NULL);
3949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3951 return (priv->account) ? g_object_ref (priv->account) : NULL;
3955 modest_mail_operation_noop (ModestMailOperation *self)
3957 ModestMailOperationPrivate *priv = NULL;
3959 g_return_if_fail (self);
3961 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3962 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3963 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3967 /* This mail operation does nothing actually */
3968 modest_mail_operation_notify_start (self);
3969 modest_mail_operation_notify_end (self);
3974 modest_mail_operation_to_string (ModestMailOperation *self)
3976 const gchar *type, *status, *account_id;
3977 ModestMailOperationPrivate *priv = NULL;
3979 g_return_val_if_fail (self, NULL);
3981 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3983 /* new operations don't have anything interesting */
3984 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3985 return g_strdup_printf ("%p <new operation>", self);
3987 switch (priv->op_type) {
3988 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3989 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
3990 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3991 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3992 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3993 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3994 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3995 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3996 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
3997 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3998 default: type = "UNEXPECTED"; break;
4001 switch (priv->status) {
4002 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4003 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4004 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4005 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4006 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4007 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4008 default: status= "UNEXPECTED"; break;
4011 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4013 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4014 priv->done, priv->total,
4015 priv->error && priv->error->message ? priv->error->message : "");
4019 * Once the mail operations were objects this will be no longer
4020 * needed. I don't like it, but we need it for the moment
4023 _check_memory_low (ModestMailOperation *mail_op)
4025 if (modest_platform_check_memory_low (NULL, FALSE)) {
4026 ModestMailOperationPrivate *priv;
4028 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4029 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4030 g_set_error (&(priv->error),
4031 MODEST_MAIL_OPERATION_ERROR,
4032 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4033 "Not enough memory to complete the operation");