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;
143 gboolean update_folder_counts;
146 static void destroy_update_account_info (UpdateAccountInfo *info);
148 static void update_account_send_mail (UpdateAccountInfo *info);
150 static void update_account_get_msg_async_cb (TnyFolder *folder,
156 static void update_account_notify_user_and_free (UpdateAccountInfo *info,
157 TnyList *new_headers);
159 enum _ModestMailOperationSignals
161 PROGRESS_CHANGED_SIGNAL,
162 OPERATION_STARTED_SIGNAL,
163 OPERATION_FINISHED_SIGNAL,
167 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
168 struct _ModestMailOperationPrivate {
174 ErrorCheckingUserCallback error_checking;
175 gpointer error_checking_user_data;
176 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
177 ModestMailOperationStatus status;
178 ModestMailOperationTypeOperation op_type;
181 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
182 MODEST_TYPE_MAIL_OPERATION, \
183 ModestMailOperationPrivate))
185 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
186 priv->status = new_status;\
191 GetMsgAsyncUserCallback user_callback;
193 TnyIterator *more_msgs;
195 ModestMailOperation *mail_op;
196 GDestroyNotify destroy_notify;
197 gint last_total_bytes;
198 gint sum_total_bytes;
200 TnyIterator *get_parts;
204 typedef struct _RefreshAsyncHelper {
205 ModestMailOperation *mail_op;
206 RefreshAsyncUserCallback user_callback;
208 } RefreshAsyncHelper;
210 typedef struct _XFerMsgsAsyncHelper
212 ModestMailOperation *mail_op;
214 TnyIterator *more_msgs;
215 TnyFolder *dest_folder;
216 XferMsgsAsyncUserCallback user_callback;
219 gint last_total_bytes;
220 gint sum_total_bytes;
222 } XFerMsgsAsyncHelper;
224 typedef struct _XFerFolderAsyncHelper
226 ModestMailOperation *mail_op;
227 XferFolderAsyncUserCallback user_callback;
229 } XFerFolderAsyncHelper;
231 typedef struct _SyncFolderHelper {
232 ModestMailOperation *mail_op;
233 SyncFolderCallback user_callback;
237 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
241 static void modest_mail_operation_create_msg (ModestMailOperation *self,
242 const gchar *from, const gchar *to,
243 const gchar *cc, const gchar *bcc,
244 const gchar *subject, const gchar *plain_body,
245 const gchar *html_body, const GList *attachments_list,
246 const GList *images_list,
247 TnyHeaderFlags priority_flags,
248 const gchar *references, const gchar *in_reply_to,
249 TnyList *header_pairs,
250 ModestMailOperationCreateMsgCallback callback,
253 static gboolean idle_notify_queue (gpointer data);
256 ModestMailOperation *mail_op;
266 GList *attachments_list;
268 TnyHeaderFlags priority_flags;
269 TnyList *header_pairs;
270 ModestMailOperationCreateMsgCallback callback;
276 ModestMailOperation *mail_op;
278 ModestMailOperationCreateMsgCallback callback;
283 static GObjectClass *parent_class = NULL;
285 static guint signals[NUM_SIGNALS] = {0};
288 modest_mail_operation_get_type (void)
290 static GType my_type = 0;
292 static const GTypeInfo my_info = {
293 sizeof(ModestMailOperationClass),
294 NULL, /* base init */
295 NULL, /* base finalize */
296 (GClassInitFunc) modest_mail_operation_class_init,
297 NULL, /* class finalize */
298 NULL, /* class data */
299 sizeof(ModestMailOperation),
301 (GInstanceInitFunc) modest_mail_operation_init,
304 my_type = g_type_register_static (G_TYPE_OBJECT,
305 "ModestMailOperation",
312 modest_mail_operation_class_init (ModestMailOperationClass *klass)
314 GObjectClass *gobject_class;
315 gobject_class = (GObjectClass*) klass;
317 parent_class = g_type_class_peek_parent (klass);
318 gobject_class->finalize = modest_mail_operation_finalize;
320 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
323 * ModestMailOperation::progress-changed
324 * @self: the #MailOperation that emits the signal
325 * @user_data: user data set when the signal handler was connected
327 * Emitted when the progress of a mail operation changes
329 signals[PROGRESS_CHANGED_SIGNAL] =
330 g_signal_new ("progress-changed",
331 G_TYPE_FROM_CLASS (gobject_class),
333 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
335 g_cclosure_marshal_VOID__POINTER,
336 G_TYPE_NONE, 1, G_TYPE_POINTER);
340 * This signal is issued whenever a mail operation starts, and
341 * starts mean when the tinymail operation is issued. This
342 * means that it could happen that something wrong happens and
343 * the tinymail function is never called. In this situation a
344 * operation-finished will be issued without any
347 signals[OPERATION_STARTED_SIGNAL] =
348 g_signal_new ("operation-started",
349 G_TYPE_FROM_CLASS (gobject_class),
351 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
353 g_cclosure_marshal_VOID__VOID,
358 * This signal is issued whenever a mail operation
359 * finishes. Note that this signal could be issued without any
360 * previous "operation-started" signal, because this last one
361 * is only issued when the tinymail operation is successfully
364 signals[OPERATION_FINISHED_SIGNAL] =
365 g_signal_new ("operation-finished",
366 G_TYPE_FROM_CLASS (gobject_class),
368 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
370 g_cclosure_marshal_VOID__VOID,
375 modest_mail_operation_init (ModestMailOperation *obj)
377 ModestMailOperationPrivate *priv;
379 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
381 priv->account = NULL;
382 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
383 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
388 priv->error_checking = NULL;
389 priv->error_checking_user_data = NULL;
393 modest_mail_operation_finalize (GObject *obj)
395 ModestMailOperationPrivate *priv;
397 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
402 g_error_free (priv->error);
406 g_object_unref (priv->source);
410 g_object_unref (priv->account);
411 priv->account = NULL;
415 G_OBJECT_CLASS(parent_class)->finalize (obj);
419 modest_mail_operation_new (GObject *source)
421 ModestMailOperation *obj;
422 ModestMailOperationPrivate *priv;
424 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
425 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
428 priv->source = g_object_ref(source);
434 modest_mail_operation_new_with_error_handling (GObject *source,
435 ErrorCheckingUserCallback error_handler,
437 ErrorCheckingUserDataDestroyer error_handler_destroyer)
439 ModestMailOperation *obj;
440 ModestMailOperationPrivate *priv;
442 obj = modest_mail_operation_new (source);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
445 g_return_val_if_fail (error_handler != NULL, obj);
446 priv->error_checking = error_handler;
447 priv->error_checking_user_data = user_data;
448 priv->error_checking_user_data_destroyer = error_handler_destroyer;
454 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
456 ModestMailOperationPrivate *priv;
458 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
460 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
461 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
463 /* Call the user callback */
464 if (priv->error_checking != NULL)
465 priv->error_checking (self, priv->error_checking_user_data);
469 ModestMailOperationTypeOperation
470 modest_mail_operation_get_type_operation (ModestMailOperation *self)
472 ModestMailOperationPrivate *priv;
474 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
475 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
479 return priv->op_type;
483 modest_mail_operation_is_mine (ModestMailOperation *self,
486 ModestMailOperationPrivate *priv;
488 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
492 if (priv->source == NULL) return FALSE;
494 return priv->source == me;
498 modest_mail_operation_get_source (ModestMailOperation *self)
500 ModestMailOperationPrivate *priv;
502 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
505 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
507 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
511 return (priv->source) ? g_object_ref (priv->source) : NULL;
514 ModestMailOperationStatus
515 modest_mail_operation_get_status (ModestMailOperation *self)
517 ModestMailOperationPrivate *priv;
519 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
520 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
521 MODEST_MAIL_OPERATION_STATUS_INVALID);
523 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
525 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
526 return MODEST_MAIL_OPERATION_STATUS_INVALID;
533 modest_mail_operation_get_error (ModestMailOperation *self)
535 ModestMailOperationPrivate *priv;
537 g_return_val_if_fail (self, NULL);
538 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
540 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
543 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
551 modest_mail_operation_cancel (ModestMailOperation *self)
553 ModestMailOperationPrivate *priv;
554 gboolean canceled = FALSE;
556 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
558 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
561 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
563 /* Cancel the mail operation */
564 g_return_val_if_fail (priv->account, FALSE);
565 tny_account_cancel (priv->account);
567 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
568 ModestTnySendQueue *queue;
569 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account),
572 /* Cancel the sending of the following next messages */
573 if (TNY_IS_SEND_QUEUE (queue))
574 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
581 modest_mail_operation_get_task_done (ModestMailOperation *self)
583 ModestMailOperationPrivate *priv;
585 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
588 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
593 modest_mail_operation_get_task_total (ModestMailOperation *self)
595 ModestMailOperationPrivate *priv;
597 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
605 modest_mail_operation_is_finished (ModestMailOperation *self)
607 ModestMailOperationPrivate *priv;
608 gboolean retval = FALSE;
610 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
613 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
615 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
616 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
617 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
618 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
628 * Creates an image of the current state of a mail operation, the
629 * caller must free it
631 static ModestMailOperationState *
632 modest_mail_operation_clone_state (ModestMailOperation *self)
634 ModestMailOperationState *state;
635 ModestMailOperationPrivate *priv;
637 g_return_val_if_fail (self, NULL);
638 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
639 g_return_val_if_fail (priv, NULL);
644 state = g_slice_new (ModestMailOperationState);
646 state->status = priv->status;
647 state->op_type = priv->op_type;
648 state->done = priv->done;
649 state->total = priv->total;
650 state->finished = modest_mail_operation_is_finished (self);
651 state->bytes_done = 0;
652 state->bytes_total = 0;
657 /* ******************************************************************* */
658 /* ************************** SEND ACTIONS ************************* */
659 /* ******************************************************************* */
663 ModestMailOperation *mail_op;
668 send_mail_on_sync_async_cb (TnyFolder *folder,
673 ModestMailOperationPrivate *priv;
674 ModestMailOperation *self;
675 SendNewMailHelper *helper;
677 helper = (SendNewMailHelper *) user_data;
678 self = helper->mail_op;
679 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
685 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
686 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
687 "Error adding a msg to the send queue\n");
688 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
690 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
695 modest_mail_operation_notify_end (self);
697 g_object_unref (helper->mail_op);
698 g_slice_free (SendNewMailHelper, helper);
702 run_queue_start (TnySendQueue *self,
705 RunQueueHelper *helper = (RunQueueHelper *) user_data;
706 ModestMailOperation *mail_op;
708 g_debug ("%s sending queue successfully started", __FUNCTION__);
710 /* Wait for the message to be sent */
711 mail_op = modest_mail_operation_new (NULL);
712 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
714 modest_mail_operation_run_queue (mail_op, helper->queue);
715 g_object_unref (mail_op);
717 /* Free the helper and end operation */
718 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
722 run_queue_error_happened (TnySendQueue *queue,
728 RunQueueHelper *helper = (RunQueueHelper *) user_data;
729 ModestMailOperationPrivate *priv;
731 /* If we are here this means that the send queue could not
732 start to send emails. Shouldn't happen as this means that
733 we could not create the thread */
734 g_debug ("%s sending queue failed to create the thread", __FUNCTION__);
736 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
737 priv->error = g_error_copy ((const GError *) error);
739 if (error->code != TNY_SYSTEM_ERROR_UNKNOWN) {
740 /* This code is here for safety reasons. It should
741 never be called, because that would mean that we
742 are not controlling some error case */
743 g_warning ("%s Error %s should not happen",
744 __FUNCTION__, error->message);
747 /* Free helper and end operation */
748 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_FAILED);
752 send_mail_on_added_to_outbox (TnySendQueue *send_queue,
758 ModestMailOperationPrivate *priv;
759 ModestMailOperation *self;
760 SendNewMailHelper *helper;
762 helper = (SendNewMailHelper *) user_data;
763 self = helper->mail_op;
764 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
770 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
771 MODEST_MAIL_OPERATION_ERROR_SEND_QUEUE_ADD_ERROR,
772 "Error adding a msg to the send queue\n");
773 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
775 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
779 if (helper->notify) {
780 TnyTransportAccount *trans_account;
781 ModestTnySendQueue *queue;
783 trans_account = (TnyTransportAccount *) modest_mail_operation_get_account (self);
785 queue = modest_runtime_get_send_queue (trans_account, TRUE);
787 RunQueueHelper *helper;
789 /* Create the helper */
790 helper = g_slice_new0 (RunQueueHelper);
791 helper->queue = g_object_ref (queue);
792 helper->self = g_object_ref (self);
794 /* if sending is ongoing wait for the queue to
795 stop. Otherwise wait for the queue-start
796 signal. It could happen that the queue
797 could not start, then check also the error
799 if (modest_tny_send_queue_sending_in_progress (queue)) {
800 run_queue_start (TNY_SEND_QUEUE (queue), helper);
802 helper->start_handler = g_signal_connect (queue, "queue-start",
803 G_CALLBACK (run_queue_start),
805 helper->error_handler = g_signal_connect (queue, "error-happened",
806 G_CALLBACK (run_queue_error_happened),
810 /* Finalize this mail operation */
811 modest_mail_operation_notify_end (self);
813 g_object_unref (trans_account);
815 g_warning ("No transport account for the operation");
819 g_object_unref (helper->mail_op);
820 g_slice_free (SendNewMailHelper, helper);
824 idle_create_msg_cb (gpointer idle_data)
826 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
828 /* This is a GDK lock because we are an idle callback and
829 * info->callback can contain Gtk+ code */
831 gdk_threads_enter (); /* CHECKED */
832 info->callback (info->mail_op, info->msg, info->userdata);
834 g_object_unref (info->mail_op);
836 g_object_unref (info->msg);
837 g_slice_free (CreateMsgIdleInfo, info);
838 gdk_threads_leave (); /* CHECKED */
844 create_msg_thread (gpointer thread_data)
846 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
847 TnyMsg *new_msg = NULL;
848 ModestMailOperationPrivate *priv;
851 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
852 if (info->html_body == NULL) {
853 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
854 info->bcc, info->subject,
855 info->references, info->in_reply_to,
857 info->attachments_list, &attached,
861 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
862 info->bcc, info->subject,
863 info->references, info->in_reply_to,
865 info->plain_body, info->attachments_list,
866 info->images_list, &attached,
872 TnyHeader *header = tny_msg_get_header (new_msg);
874 /* Set priority flags in message */
875 if (info->priority_flags != TNY_HEADER_FLAG_NORMAL_PRIORITY)
876 tny_header_set_flag (header, info->priority_flags);
878 /* Set attachment flags in message */
879 if (info->attachments_list != NULL && attached > 0)
880 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
882 g_object_unref (G_OBJECT(header));
884 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
886 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
887 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
888 "modest: failed to create a new msg\n");
896 g_free (info->plain_body);
897 g_free (info->html_body);
898 g_free (info->subject);
899 g_free (info->references);
900 g_free (info->in_reply_to);
901 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
902 g_list_free (info->attachments_list);
903 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
904 g_list_free (info->images_list);
905 g_object_unref (info->header_pairs);
907 if (info->callback) {
908 CreateMsgIdleInfo *idle_info;
909 idle_info = g_slice_new0 (CreateMsgIdleInfo);
910 idle_info->mail_op = g_object_ref (info->mail_op);
911 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
912 idle_info->callback = info->callback;
913 idle_info->userdata = info->userdata;
914 g_idle_add (idle_create_msg_cb, idle_info);
916 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
919 g_object_unref (info->mail_op);
920 g_slice_free (CreateMsgInfo, info);
921 if (new_msg) g_object_unref(new_msg);
927 modest_mail_operation_create_msg (ModestMailOperation *self,
928 const gchar *from, const gchar *to,
929 const gchar *cc, const gchar *bcc,
930 const gchar *subject, const gchar *plain_body,
931 const gchar *html_body,
932 const GList *attachments_list,
933 const GList *images_list,
934 TnyHeaderFlags priority_flags,
935 const gchar *references,
936 const gchar *in_reply_to,
937 TnyList *header_pairs,
938 ModestMailOperationCreateMsgCallback callback,
941 CreateMsgInfo *info = NULL;
943 info = g_slice_new0 (CreateMsgInfo);
944 info->mail_op = g_object_ref (self);
946 info->from = g_strdup (from);
947 info->to = g_strdup (to);
948 info->cc = g_strdup (cc);
949 info->bcc = g_strdup (bcc);
950 info->subject = g_strdup (subject);
951 info->plain_body = g_strdup (plain_body);
952 info->html_body = g_strdup (html_body);
953 info->references = g_strdup (references);
954 info->in_reply_to = g_strdup (in_reply_to);
955 info->attachments_list = g_list_copy ((GList *) attachments_list);
956 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
957 info->images_list = g_list_copy ((GList *) images_list);
958 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
959 info->priority_flags = 0 | priority_flags;
960 info->header_pairs = tny_list_copy (header_pairs);
962 info->callback = callback;
963 info->userdata = userdata;
965 g_thread_create (create_msg_thread, info, FALSE, NULL);
970 TnyTransportAccount *transport_account;
975 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
979 TnySendQueue *send_queue = NULL;
980 ModestMailOperationPrivate *priv = NULL;
981 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
982 TnyFolder *draft_folder = NULL;
983 TnyFolder *outbox_folder = NULL;
984 TnyHeader *header = NULL;
986 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
989 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
990 modest_mail_operation_notify_end (self);
994 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
995 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
996 modest_mail_operation_notify_end (self);
1000 /* Add message to send queue */
1001 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (info->transport_account, TRUE));
1002 if (!TNY_IS_SEND_QUEUE(send_queue)) {
1004 g_error_free (priv->error);
1007 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1008 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1009 "modest: could not find send queue for account\n");
1010 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1011 modest_mail_operation_notify_end (self);
1014 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
1015 helper->mail_op = g_object_ref (self);
1016 helper->notify = (info->draft_msg == NULL);
1018 /* Add the msg to the queue. The callback will free
1020 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1022 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1026 if (info->draft_msg != NULL) {
1027 TnyList *tmp_headers = NULL;
1028 TnyFolder *folder = NULL;
1029 TnyFolder *src_folder = NULL;
1030 TnyFolderType folder_type;
1031 TnyTransportAccount *transport_account = NULL;
1032 SendNewMailHelper *helper = NULL;
1034 /* To remove the old mail from its source folder, we need to get the
1035 * transport account of the original draft message (the transport account
1036 * might have been changed by the user) */
1037 header = tny_msg_get_header (info->draft_msg);
1038 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
1039 modest_runtime_get_account_store(), header);
1040 if (transport_account == NULL)
1041 transport_account = g_object_ref(info->transport_account);
1042 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1043 TNY_FOLDER_TYPE_DRAFTS);
1044 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
1045 TNY_FOLDER_TYPE_OUTBOX);
1046 g_object_unref(transport_account);
1048 if (!draft_folder) {
1049 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
1051 modest_mail_operation_notify_end (self);
1054 if (!outbox_folder) {
1055 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
1057 modest_mail_operation_notify_end (self);
1061 folder = tny_msg_get_folder (info->draft_msg);
1062 if (folder == NULL) {
1063 modest_mail_operation_notify_end (self);
1066 folder_type = modest_tny_folder_guess_folder_type (folder);
1068 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1069 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1071 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
1072 src_folder = outbox_folder;
1074 src_folder = draft_folder;
1076 /* Note: This can fail (with a warning) if the message is not really already in a folder,
1077 * because this function requires it to have a UID. */
1078 helper = g_slice_new (SendNewMailHelper);
1079 helper->mail_op = g_object_ref (self);
1080 helper->notify = TRUE;
1082 tmp_headers = tny_simple_list_new ();
1083 tny_list_append (tmp_headers, (GObject*) header);
1084 tny_folder_remove_msgs_async (src_folder, tmp_headers, NULL, NULL, NULL);
1085 g_object_unref (tmp_headers);
1086 tny_folder_sync_async (src_folder, TRUE, send_mail_on_sync_async_cb,
1088 g_object_unref (folder);
1093 g_object_unref (header);
1094 if (info->draft_msg)
1095 g_object_unref (info->draft_msg);
1097 g_object_unref (draft_folder);
1099 g_object_unref (outbox_folder);
1100 if (info->transport_account)
1101 g_object_unref (info->transport_account);
1102 g_slice_free (SendNewMailInfo, info);
1106 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1107 TnyTransportAccount *transport_account,
1109 const gchar *from, const gchar *to,
1110 const gchar *cc, const gchar *bcc,
1111 const gchar *subject, const gchar *plain_body,
1112 const gchar *html_body,
1113 const GList *attachments_list,
1114 const GList *images_list,
1115 const gchar *references,
1116 const gchar *in_reply_to,
1117 TnyHeaderFlags priority_flags,
1118 TnyList *header_pairs)
1120 ModestMailOperationPrivate *priv = NULL;
1121 SendNewMailInfo *info;
1123 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1124 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1126 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1127 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1128 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1129 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1131 modest_mail_operation_notify_start (self);
1133 /* Check parametters */
1135 /* Set status failed and set an error */
1136 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1137 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1138 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1139 _("Error trying to send a mail. You need to set at least one recipient"));
1140 modest_mail_operation_notify_end (self);
1143 info = g_slice_new0 (SendNewMailInfo);
1144 info->transport_account = transport_account;
1145 if (transport_account)
1146 g_object_ref (transport_account);
1147 info->draft_msg = draft_msg;
1149 g_object_ref (draft_msg);
1152 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1153 attachments_list, images_list, priority_flags,
1154 references, in_reply_to,
1156 modest_mail_operation_send_new_mail_cb, info);
1162 ModestMailOperation *mailop;
1164 SaveToDraftstCallback callback;
1166 } FinishSaveRemoteDraftInfo;
1169 finish_save_remote_draft (ModestAccountProtocol *protocol,
1171 const gchar *account_id,
1172 TnyMsg *new_remote_msg,
1177 FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
1178 ModestMailOperationPrivate *priv = NULL;
1180 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1182 if (!priv->error && err != NULL) {
1183 /* Priority for errors in save to local stage */
1184 priv->error = g_error_copy (err);
1185 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1189 info->callback (info->mailop, info->msg, info->userdata);
1192 g_object_unref (info->msg);
1194 modest_mail_operation_notify_end (info->mailop);
1195 g_object_unref (info->mailop);
1197 g_slice_free (FinishSaveRemoteDraftInfo, info);
1202 TnyTransportAccount *transport_account;
1204 SaveToDraftstCallback callback;
1208 ModestMailOperation *mailop;
1209 } SaveToDraftsAddMsgInfo;
1212 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1217 ModestMailOperationPrivate *priv = NULL;
1218 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1219 GError *io_error = NULL;
1220 gboolean callback_called = FALSE;
1222 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1224 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1225 io_error = priv->error;
1229 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1230 g_error_free(priv->error);
1233 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1235 if ((!priv->error) && (info->draft_msg != NULL)) {
1236 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1237 TnyFolder *src_folder = tny_header_get_folder (header);
1239 g_debug ("--- REMOVE AND SYNC");
1240 /* Remove the old draft */
1241 tny_folder_remove_msg (src_folder, header, NULL);
1243 /* Synchronize to expunge and to update the msg counts */
1244 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1245 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1246 g_debug ("--- REMOVED - SYNCED");
1248 g_object_unref (G_OBJECT(header));
1249 g_object_unref (G_OBJECT(src_folder));
1253 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1255 g_error_free (io_error);
1258 } else if (io_error) {
1259 priv->error = io_error;
1260 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1262 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1265 if (info->transport_account) {
1266 ModestProtocolType transport_protocol_type;
1267 ModestProtocol *transport_protocol;
1269 transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
1271 transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1272 transport_protocol_type);
1273 if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
1274 FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
1275 srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
1276 srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
1277 srd_info->callback = info->callback;
1278 srd_info->userdata = info->user_data;
1279 modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol),
1280 tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
1281 info->msg, info->draft_msg,
1282 finish_save_remote_draft,
1285 callback_called = TRUE;
1289 /* Call the user callback */
1290 if (!callback_called && info->callback)
1291 info->callback (info->mailop, info->msg, info->user_data);
1293 if (info->transport_account)
1294 g_object_unref (G_OBJECT(info->transport_account));
1295 if (info->draft_msg)
1296 g_object_unref (G_OBJECT (info->draft_msg));
1298 g_object_unref (G_OBJECT(info->drafts));
1300 g_object_unref (G_OBJECT (info->msg));
1302 if (!callback_called)
1303 modest_mail_operation_notify_end (info->mailop);
1305 g_object_unref(info->mailop);
1306 g_slice_free (SaveToDraftsAddMsgInfo, info);
1311 TnyTransportAccount *transport_account;
1313 SaveToDraftstCallback callback;
1318 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1322 TnyFolder *drafts = NULL;
1323 ModestMailOperationPrivate *priv = NULL;
1324 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1326 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1329 if (!(priv->error)) {
1330 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1331 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1332 "modest: failed to create a new msg\n");
1335 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1336 TNY_FOLDER_TYPE_DRAFTS);
1337 if (!drafts && !(priv->error)) {
1338 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1339 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1340 "modest: failed to create a new msg\n");
1344 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1346 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1347 cb_info->transport_account = g_object_ref(info->transport_account);
1348 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1349 cb_info->callback = info->callback;
1350 cb_info->user_data = info->user_data;
1351 cb_info->drafts = g_object_ref(drafts);
1352 cb_info->msg = g_object_ref(msg);
1353 cb_info->mailop = g_object_ref(self);
1354 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1358 /* Call the user callback */
1359 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1361 info->callback (self, msg, info->user_data);
1362 modest_mail_operation_notify_end (self);
1366 g_object_unref (G_OBJECT(drafts));
1367 if (info->draft_msg)
1368 g_object_unref (G_OBJECT (info->draft_msg));
1369 if (info->transport_account)
1370 g_object_unref (G_OBJECT(info->transport_account));
1371 g_slice_free (SaveToDraftsInfo, info);
1375 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1376 TnyTransportAccount *transport_account,
1378 const gchar *from, const gchar *to,
1379 const gchar *cc, const gchar *bcc,
1380 const gchar *subject, const gchar *plain_body,
1381 const gchar *html_body,
1382 const GList *attachments_list,
1383 const GList *images_list,
1384 TnyHeaderFlags priority_flags,
1385 const gchar *references,
1386 const gchar *in_reply_to,
1387 TnyList *header_pairs,
1388 SaveToDraftstCallback callback,
1391 ModestMailOperationPrivate *priv = NULL;
1392 SaveToDraftsInfo *info = NULL;
1394 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1395 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1397 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1399 /* Get account and set it into mail_operation */
1400 priv->account = g_object_ref (transport_account);
1401 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1403 info = g_slice_new0 (SaveToDraftsInfo);
1404 info->transport_account = g_object_ref (transport_account);
1405 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1406 info->callback = callback;
1407 info->user_data = user_data;
1409 g_debug ("--- CREATE MESSAGE");
1410 modest_mail_operation_notify_start (self);
1411 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1412 attachments_list, images_list, priority_flags,
1413 references, in_reply_to,
1415 modest_mail_operation_save_to_drafts_cb, info);
1420 ModestMailOperation *mail_op;
1421 TnyMimePart *mime_part;
1423 GetMimePartSizeCallback callback;
1425 } GetMimePartSizeInfo;
1427 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1428 /* We use this folder observer to track the headers that have been
1429 * added to a folder */
1432 TnyList *new_headers;
1433 } InternalFolderObserver;
1436 GObjectClass parent;
1437 } InternalFolderObserverClass;
1439 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1441 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1442 internal_folder_observer,
1444 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1448 foreach_add_item (gpointer header, gpointer user_data)
1450 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1453 /* This is the method that looks for new messages in a folder */
1455 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1457 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1459 TnyFolderChangeChanged changed;
1461 changed = tny_folder_change_get_changed (change);
1463 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1466 /* Get added headers */
1467 list = tny_simple_list_new ();
1468 tny_folder_change_get_added_headers (change, list);
1470 /* Add them to the folder observer */
1471 tny_list_foreach (list, foreach_add_item,
1472 derived->new_headers);
1474 g_object_unref (G_OBJECT (list));
1479 internal_folder_observer_init (InternalFolderObserver *self)
1481 self->new_headers = tny_simple_list_new ();
1484 internal_folder_observer_finalize (GObject *object)
1486 InternalFolderObserver *self;
1488 self = (InternalFolderObserver *) object;
1489 g_object_unref (self->new_headers);
1491 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1494 tny_folder_observer_init (TnyFolderObserverIface *iface)
1496 iface->update = internal_folder_observer_update;
1499 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1501 GObjectClass *object_class;
1503 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1504 object_class = (GObjectClass*) klass;
1505 object_class->finalize = internal_folder_observer_finalize;
1509 destroy_update_account_info (UpdateAccountInfo *info)
1511 g_free (info->account_name);
1512 g_object_unref (info->folders);
1513 g_object_unref (info->mail_op);
1514 g_slice_free (UpdateAccountInfo, info);
1519 update_account_send_mail (UpdateAccountInfo *info)
1521 TnyTransportAccount *transport_account = NULL;
1522 ModestTnyAccountStore *account_store;
1524 if (info->update_folder_counts)
1527 account_store = modest_runtime_get_account_store ();
1529 /* We don't try to send messages while sending mails is blocked */
1530 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1533 /* Get the transport account */
1534 transport_account = (TnyTransportAccount *)
1535 modest_tny_account_store_get_server_account (account_store, info->account_name,
1536 TNY_ACCOUNT_TYPE_TRANSPORT);
1538 if (transport_account) {
1539 ModestTnySendQueue *send_queue;
1543 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1544 g_object_unref (transport_account);
1546 if (TNY_IS_SEND_QUEUE (send_queue)) {
1547 /* Get outbox folder */
1548 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1549 if (outbox) { /* this could fail in some cases */
1550 num_messages = tny_folder_get_all_count (outbox);
1551 g_object_unref (outbox);
1553 g_warning ("%s: could not get outbox", __FUNCTION__);
1557 if (num_messages != 0) {
1558 ModestMailOperation *mail_op;
1559 /* Reenable suspended items */
1560 mail_op = modest_mail_operation_new (NULL);
1561 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1563 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1566 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1574 update_account_get_msg_async_cb (TnyFolder *folder,
1580 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1581 ModestMailOperationPrivate *priv;
1583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1586 if (TNY_IS_MSG (msg)) {
1587 TnyHeader *header = tny_msg_get_header (msg);
1590 ModestMailOperationState *state;
1591 state = modest_mail_operation_clone_state (msg_info->mail_op);
1592 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1593 state->bytes_done = msg_info->sum_total_bytes;
1594 state->bytes_total = msg_info->total_bytes;
1596 /* Notify the status change. Only notify about changes
1597 referred to bytes */
1598 g_signal_emit (G_OBJECT (msg_info->mail_op),
1599 signals[PROGRESS_CHANGED_SIGNAL],
1602 g_object_unref (header);
1603 g_slice_free (ModestMailOperationState, state);
1607 if (priv->done == priv->total) {
1608 TnyList *new_headers;
1609 UpdateAccountInfo *info;
1611 /* After getting all the messages send the ones in the
1613 info = (UpdateAccountInfo *) msg_info->user_data;
1614 update_account_send_mail (info);
1616 /* Check if the operation was a success */
1618 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1620 /* Call the user callback and free */
1621 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1622 update_account_notify_user_and_free (info, new_headers);
1624 /* Delete the helper */
1626 g_object_unref (msg_info->msg);
1627 g_object_unref (msg_info->more_msgs);
1628 g_object_unref (msg_info->mail_op);
1629 g_slice_free (GetMsgInfo, msg_info);
1634 update_account_notify_user_and_free (UpdateAccountInfo *info,
1635 TnyList *new_headers)
1637 /* Set the account back to not busy */
1638 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1639 info->account_name, FALSE);
1643 info->callback (info->mail_op, new_headers, info->user_data);
1645 /* Mail operation end */
1646 modest_mail_operation_notify_end (info->mail_op);
1650 g_object_unref (new_headers);
1651 destroy_update_account_info (info);
1655 inbox_refreshed_cb (TnyFolder *inbox,
1660 UpdateAccountInfo *info;
1661 ModestMailOperationPrivate *priv;
1662 TnyIterator *new_headers_iter;
1663 GPtrArray *new_headers_array = NULL;
1664 gint max_size = G_MAXINT, retrieve_limit, i;
1665 ModestAccountMgr *mgr;
1666 ModestAccountRetrieveType retrieve_type;
1667 TnyList *new_headers = NULL;
1668 gboolean headers_only;
1669 time_t time_to_store;
1671 info = (UpdateAccountInfo *) user_data;
1672 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1673 mgr = modest_runtime_get_account_mgr ();
1675 if (canceled || err) {
1676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1678 priv->error = g_error_copy (err);
1680 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1681 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1685 tny_folder_remove_observer (inbox, info->inbox_observer);
1686 g_object_unref (info->inbox_observer);
1687 info->inbox_observer = NULL;
1689 /* Notify the user about the error and then exit */
1690 update_account_notify_user_and_free (info, NULL);
1695 /* Try to send anyway */
1699 if (!info->update_folder_counts) {
1700 /* Set the last updated as the current time */
1701 #ifdef MODEST_USE_LIBTIME
1703 time_get_utc (&utc_tm);
1704 time_to_store = time_mktime (&utc_tm, "GMT");
1706 time_to_store = time (NULL);
1708 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
1710 /* Get the message max size */
1711 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1712 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1714 max_size = G_MAXINT;
1716 max_size = max_size * KB;
1719 /* Create the new headers array. We need it to sort the
1720 new headers by date */
1721 new_headers_array = g_ptr_array_new ();
1722 if (info->inbox_observer) {
1723 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1724 if (!tny_iterator_is_done (new_headers_iter)) {
1725 modest_platform_emit_folder_updated_signal (info->account_name, tny_folder_get_id (TNY_FOLDER (inbox)));
1727 while (!tny_iterator_is_done (new_headers_iter)) {
1728 TnyHeader *header = NULL;
1730 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1731 /* Apply per-message size limits */
1732 if (tny_header_get_message_size (header) < max_size)
1733 g_ptr_array_add (new_headers_array, g_object_ref (header));
1735 g_object_unref (header);
1736 tny_iterator_next (new_headers_iter);
1738 g_object_unref (new_headers_iter);
1740 tny_folder_remove_observer (inbox, info->inbox_observer);
1741 g_object_unref (info->inbox_observer);
1742 info->inbox_observer = NULL;
1745 if (new_headers_array->len == 0) {
1746 g_ptr_array_free (new_headers_array, FALSE);
1750 /* Get per-account message amount retrieval limit */
1751 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1752 if (retrieve_limit == 0)
1753 retrieve_limit = G_MAXINT;
1755 /* Get per-account retrieval type */
1756 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1757 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1760 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1762 /* Copy the headers to a list and free the array */
1763 new_headers = tny_simple_list_new ();
1764 for (i=0; i < new_headers_array->len; i++) {
1765 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1766 /* We want the first element to be the most recent
1767 one, that's why we reverse the list */
1768 tny_list_prepend (new_headers, G_OBJECT (header));
1770 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1771 g_ptr_array_free (new_headers_array, FALSE);
1773 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1776 GetMsgInfo *msg_info;
1779 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1781 iter = tny_list_create_iterator (new_headers);
1783 /* Create the message info */
1784 msg_info = g_slice_new0 (GetMsgInfo);
1785 msg_info->mail_op = g_object_ref (info->mail_op);
1786 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1787 msg_info->more_msgs = g_object_ref (iter);
1788 msg_info->msg = NULL;
1789 msg_info->user_data = info;
1791 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1792 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1793 TnyFolder *folder = tny_header_get_folder (header);
1795 /* Get message in an async way */
1796 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1799 g_object_unref (folder);
1800 g_object_unref (header);
1803 tny_iterator_next (iter);
1805 g_object_unref (iter);
1806 g_object_unref (new_headers);
1808 /* The mail operation will finish when the last
1809 message is retrieved */
1813 /* If we don't have to retrieve the new messages then
1815 update_account_send_mail (info);
1817 /* Check if the operation was a success */
1819 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1821 /* Call the user callback and free */
1822 update_account_notify_user_and_free (info, new_headers);
1826 inbox_refresh_status_update (GObject *obj,
1830 UpdateAccountInfo *info = NULL;
1831 ModestMailOperation *self = NULL;
1832 ModestMailOperationPrivate *priv = NULL;
1833 ModestMailOperationState *state;
1835 g_return_if_fail (user_data != NULL);
1836 g_return_if_fail (status != NULL);
1838 /* Show only the status information we want */
1839 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1842 info = (UpdateAccountInfo *) user_data;
1843 self = info->mail_op;
1844 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1846 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1848 priv->done = status->position;
1849 priv->total = status->of_total;
1851 state = modest_mail_operation_clone_state (self);
1853 /* This is not a GDK lock because we are a Tinymail callback and
1854 * Tinymail already acquires the Gdk lock */
1855 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1857 g_slice_free (ModestMailOperationState, state);
1861 recurse_folders_async_cb (TnyFolderStore *folder_store,
1867 UpdateAccountInfo *info;
1868 ModestMailOperationPrivate *priv;
1870 info = (UpdateAccountInfo *) user_data;
1871 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1873 if (err || canceled) {
1874 /* If the error was previosly set by another callback
1875 don't set it again */
1877 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1879 priv->error = g_error_copy (err);
1881 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1882 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1886 /* We're not getting INBOX children if we don't want to poke all */
1887 TnyIterator *iter = tny_list_create_iterator (list);
1888 while (!tny_iterator_is_done (iter)) {
1889 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1891 /* Add to the list of all folders */
1892 tny_list_append (info->folders, (GObject *) folder);
1894 if (info->poke_all) {
1895 TnyList *folders = tny_simple_list_new ();
1896 /* Add pending call */
1897 info->pending_calls++;
1899 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1900 recurse_folders_async_cb,
1902 g_object_unref (folders);
1905 g_object_unref (G_OBJECT (folder));
1907 tny_iterator_next (iter);
1909 g_object_unref (G_OBJECT (iter));
1912 /* Remove my own pending call */
1913 info->pending_calls--;
1915 /* This means that we have all the folders */
1916 if (info->pending_calls == 0) {
1917 TnyIterator *iter_all_folders;
1918 TnyFolder *inbox = NULL;
1920 /* If there was any error do not continue */
1922 update_account_notify_user_and_free (info, NULL);
1926 iter_all_folders = tny_list_create_iterator (info->folders);
1928 /* Do a poke status over all folders */
1929 while (!tny_iterator_is_done (iter_all_folders) &&
1930 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1931 TnyFolder *folder = NULL;
1933 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1935 if (!info->update_folder_counts && tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1936 /* Get a reference to the INBOX */
1937 inbox = g_object_ref (folder);
1939 /* Issue a poke status over the folder */
1941 tny_folder_poke_status (folder);
1944 /* Free and go to next */
1945 g_object_unref (folder);
1946 tny_iterator_next (iter_all_folders);
1948 g_object_unref (iter_all_folders);
1950 /* Refresh the INBOX */
1952 /* Refresh the folder. Our observer receives
1953 * the new emails during folder refreshes, so
1954 * we can use observer->new_headers
1956 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1957 tny_folder_add_observer (inbox, info->inbox_observer);
1959 /* Refresh the INBOX */
1960 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
1961 g_object_unref (inbox);
1963 /* We could not perform the inbox refresh but
1964 we'll try to send mails anyway */
1965 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1971 modest_mail_operation_update_account (ModestMailOperation *self,
1972 const gchar *account_name,
1974 gboolean interactive,
1975 UpdateAccountCallback callback,
1978 UpdateAccountInfo *info = NULL;
1979 ModestMailOperationPrivate *priv = NULL;
1980 ModestTnyAccountStore *account_store = NULL;
1982 ModestMailOperationState *state;
1984 /* Init mail operation */
1985 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1988 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1989 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1991 /* Get the store account */
1992 account_store = modest_runtime_get_account_store ();
1994 modest_tny_account_store_get_server_account (account_store,
1996 TNY_ACCOUNT_TYPE_STORE);
1998 /* The above function could return NULL */
1999 if (!priv->account) {
2000 /* Check if the operation was a success */
2001 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2002 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2004 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2006 /* Call the user callback */
2008 callback (self, NULL, user_data);
2010 /* Notify about operation end */
2011 modest_mail_operation_notify_end (self);
2016 /* We have once seen priv->account getting finalized during this code,
2017 * therefore adding a reference (bug #82296) */
2019 g_object_ref (priv->account);
2021 /* Create the helper object */
2022 info = g_slice_new0 (UpdateAccountInfo);
2023 info->pending_calls = 1;
2024 info->folders = tny_simple_list_new ();
2025 info->mail_op = g_object_ref (self);
2026 info->poke_all = poke_all;
2027 info->interactive = interactive;
2028 info->update_folder_counts = FALSE;
2029 info->account_name = g_strdup (account_name);
2030 info->callback = callback;
2031 info->user_data = user_data;
2033 /* Set account busy */
2034 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2035 modest_mail_operation_notify_start (self);
2037 /* notify about the start of the operation */
2038 state = modest_mail_operation_clone_state (self);
2042 /* Start notifying progress */
2043 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2044 g_slice_free (ModestMailOperationState, state);
2046 /* Get all folders and continue in the callback */
2047 folders = tny_simple_list_new ();
2048 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2049 folders, NULL, TRUE,
2050 recurse_folders_async_cb,
2052 g_object_unref (folders);
2054 g_object_unref (priv->account);
2059 modest_mail_operation_update_folder_counts (ModestMailOperation *self,
2060 const gchar *account_name)
2062 UpdateAccountInfo *info = NULL;
2063 ModestMailOperationPrivate *priv = NULL;
2064 ModestTnyAccountStore *account_store = NULL;
2066 ModestMailOperationState *state;
2068 /* Init mail operation */
2069 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2072 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2073 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UPDATE_FOLDER_COUNTS;
2075 /* Get the store account */
2076 account_store = modest_runtime_get_account_store ();
2078 modest_tny_account_store_get_server_account (account_store,
2080 TNY_ACCOUNT_TYPE_STORE);
2082 /* The above function could return NULL */
2083 if (!priv->account) {
2084 /* Check if the operation was a success */
2085 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2086 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2088 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2090 /* Notify about operation end */
2091 modest_mail_operation_notify_end (self);
2096 /* We have once seen priv->account getting finalized during this code,
2097 * therefore adding a reference (bug #82296) */
2099 g_object_ref (priv->account);
2101 /* Create the helper object */
2102 info = g_slice_new0 (UpdateAccountInfo);
2103 info->pending_calls = 1;
2104 info->folders = tny_simple_list_new ();
2105 info->mail_op = g_object_ref (self);
2106 info->poke_all = TRUE;
2107 info->interactive = FALSE;
2108 info->update_folder_counts = TRUE;
2109 info->account_name = g_strdup (account_name);
2110 info->callback = NULL;
2111 info->user_data = NULL;
2113 /* Set account busy */
2114 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2115 modest_mail_operation_notify_start (self);
2117 /* notify about the start of the operation */
2118 state = modest_mail_operation_clone_state (self);
2122 /* Start notifying progress */
2123 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2124 g_slice_free (ModestMailOperationState, state);
2126 /* Get all folders and continue in the callback */
2127 folders = tny_simple_list_new ();
2128 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2129 folders, NULL, TRUE,
2130 recurse_folders_async_cb,
2132 g_object_unref (folders);
2134 g_object_unref (priv->account);
2139 * Used to notify the queue from the main
2140 * loop. We call it inside an idle call to achieve that
2143 idle_notify_queue (gpointer data)
2145 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2147 gdk_threads_enter ();
2148 modest_mail_operation_notify_end (mail_op);
2149 gdk_threads_leave ();
2150 g_object_unref (mail_op);
2156 compare_headers_by_date (gconstpointer a,
2159 TnyHeader **header1, **header2;
2160 time_t sent1, sent2;
2162 header1 = (TnyHeader **) a;
2163 header2 = (TnyHeader **) b;
2165 sent1 = tny_header_get_date_sent (*header1);
2166 sent2 = tny_header_get_date_sent (*header2);
2168 /* We want the most recent ones (greater time_t) at the
2177 /* ******************************************************************* */
2178 /* ************************** STORE ACTIONS ************************* */
2179 /* ******************************************************************* */
2182 ModestMailOperation *mail_op;
2183 CreateFolderUserCallback callback;
2189 create_folder_cb (TnyFolderStore *parent_folder,
2191 TnyFolder *new_folder,
2195 ModestMailOperationPrivate *priv;
2196 CreateFolderInfo *info;
2198 info = (CreateFolderInfo *) user_data;
2199 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2201 if (canceled || err) {
2202 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2204 priv->error = g_error_copy (err);
2206 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2207 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2210 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2213 /* The user will unref the new_folder */
2215 info->callback (info->mail_op, parent_folder,
2216 new_folder, info->user_data);
2218 /* Notify about operation end */
2219 modest_mail_operation_notify_end (info->mail_op);
2222 g_object_unref (info->mail_op);
2223 g_slice_free (CreateFolderInfo, info);
2227 modest_mail_operation_create_folder (ModestMailOperation *self,
2228 TnyFolderStore *parent,
2230 CreateFolderUserCallback callback,
2233 ModestMailOperationPrivate *priv;
2235 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2236 g_return_if_fail (name);
2238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2239 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2240 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2241 g_object_ref (parent) :
2242 modest_tny_folder_get_account (TNY_FOLDER (parent));
2244 /* Check for already existing folder */
2245 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2246 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2247 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2248 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2249 _CS("ckdg_ib_folder_already_exists"));
2253 if (TNY_IS_FOLDER (parent)) {
2254 /* Check folder rules */
2255 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2256 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2257 /* Set status failed and set an error */
2258 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2259 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2260 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2261 _("mail_in_ui_folder_create_error"));
2265 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2266 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2267 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2268 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2269 _("mail_in_ui_folder_create_error"));
2273 CreateFolderInfo *info;
2275 info = g_slice_new0 (CreateFolderInfo);
2276 info->mail_op = g_object_ref (self);
2277 info->callback = callback;
2278 info->user_data = user_data;
2280 modest_mail_operation_notify_start (self);
2282 /* Create the folder */
2283 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2286 /* Call the user callback anyway */
2288 callback (self, parent, NULL, user_data);
2289 /* Notify about operation end */
2290 modest_mail_operation_notify_end (self);
2295 modest_mail_operation_remove_folder (ModestMailOperation *self,
2297 gboolean remove_to_trash)
2299 ModestMailOperationPrivate *priv;
2300 ModestTnyFolderRules rules;
2302 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2303 g_return_if_fail (TNY_IS_FOLDER (folder));
2305 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2307 /* Check folder rules */
2308 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2309 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2310 /* Set status failed and set an error */
2311 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2312 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2313 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2314 _("mail_in_ui_folder_delete_error"));
2318 /* Get the account */
2319 priv->account = modest_tny_folder_get_account (folder);
2320 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2322 /* Delete folder or move to trash */
2323 if (remove_to_trash) {
2324 TnyFolder *trash_folder = NULL;
2325 trash_folder = modest_tny_account_get_special_folder (priv->account,
2326 TNY_FOLDER_TYPE_TRASH);
2327 /* TODO: error_handling */
2329 modest_mail_operation_notify_start (self);
2330 modest_mail_operation_xfer_folder (self, folder,
2331 TNY_FOLDER_STORE (trash_folder),
2333 g_object_unref (trash_folder);
2335 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2338 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2340 modest_mail_operation_notify_start (self);
2341 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2342 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2345 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2347 g_object_unref (parent);
2349 g_warning ("%s: could not get parent folder", __FUNCTION__);
2353 /* Notify about operation end */
2354 modest_mail_operation_notify_end (self);
2358 transfer_folder_status_cb (GObject *obj,
2362 ModestMailOperation *self;
2363 ModestMailOperationPrivate *priv;
2364 ModestMailOperationState *state;
2365 XFerFolderAsyncHelper *helper;
2367 g_return_if_fail (status != NULL);
2369 /* Show only the status information we want */
2370 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2373 helper = (XFerFolderAsyncHelper *) user_data;
2374 g_return_if_fail (helper != NULL);
2376 self = helper->mail_op;
2377 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2379 priv->done = status->position;
2380 priv->total = status->of_total;
2382 state = modest_mail_operation_clone_state (self);
2384 /* This is not a GDK lock because we are a Tinymail callback
2385 * which is already GDK locked by Tinymail */
2387 /* no gdk_threads_enter (), CHECKED */
2389 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2391 /* no gdk_threads_leave (), CHECKED */
2393 g_slice_free (ModestMailOperationState, state);
2397 transfer_folder_cb (TnyFolder *folder,
2399 TnyFolderStore *into,
2400 TnyFolder *new_folder,
2404 XFerFolderAsyncHelper *helper;
2405 ModestMailOperation *self = NULL;
2406 ModestMailOperationPrivate *priv = NULL;
2408 helper = (XFerFolderAsyncHelper *) user_data;
2409 g_return_if_fail (helper != NULL);
2411 self = helper->mail_op;
2412 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2415 priv->error = g_error_copy (err);
2417 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2418 } else if (cancelled) {
2419 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2420 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2421 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2422 _("Transference of %s was cancelled."),
2423 tny_folder_get_name (folder));
2426 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2429 /* Update state of new folder */
2431 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2432 tny_folder_poke_status (new_folder);
2435 /* Notify about operation end */
2436 modest_mail_operation_notify_end (self);
2438 /* If user defined callback function was defined, call it */
2439 if (helper->user_callback) {
2441 /* This is not a GDK lock because we are a Tinymail callback
2442 * which is already GDK locked by Tinymail */
2444 /* no gdk_threads_enter (), CHECKED */
2445 helper->user_callback (self, new_folder, helper->user_data);
2446 /* no gdk_threads_leave () , CHECKED */
2450 g_object_unref (helper->mail_op);
2451 g_slice_free (XFerFolderAsyncHelper, helper);
2456 * This function checks if the new name is a valid name for our local
2457 * folders account. The new name could not be the same than then name
2458 * of any of the mandatory local folders
2460 * We can not rely on tinymail because tinymail does not check the
2461 * name of the virtual folders that the account could have in the case
2462 * that we're doing a rename (because it directly calls Camel which
2463 * knows nothing about our virtual folders).
2465 * In the case of an actual copy/move (i.e. move/copy a folder between
2466 * accounts) tinymail uses the tny_folder_store_create_account which
2467 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2468 * checks the new name of the folder, so this call in that case
2469 * wouldn't be needed. *But* NOTE that if tinymail changes its
2470 * implementation (if folder transfers within the same account is no
2471 * longer implemented as a rename) this call will allow Modest to work
2474 * If the new name is not valid, this function will set the status to
2475 * failed and will set also an error in the mail operation
2478 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2479 TnyFolderStore *into,
2480 const gchar *new_name)
2482 if (TNY_IS_ACCOUNT (into) &&
2483 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2484 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2486 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2487 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2488 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2489 _CS("ckdg_ib_folder_already_exists"));
2496 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2498 TnyFolderStore *parent,
2499 gboolean delete_original,
2500 XferFolderAsyncUserCallback user_callback,
2503 ModestMailOperationPrivate *priv = NULL;
2504 ModestTnyFolderRules parent_rules = 0, rules;
2505 XFerFolderAsyncHelper *helper = NULL;
2506 const gchar *folder_name = NULL;
2507 const gchar *error_msg;
2509 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2510 g_return_if_fail (TNY_IS_FOLDER (folder));
2511 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2513 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2514 folder_name = tny_folder_get_name (folder);
2516 /* Set the error msg */
2517 error_msg = _("mail_in_ui_folder_move_target_error");
2519 /* Get account and set it into mail_operation */
2520 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2521 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2522 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2524 /* Get folder rules */
2525 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2526 if (TNY_IS_FOLDER (parent))
2527 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2529 /* Apply operation constraints */
2530 if ((gpointer) parent == (gpointer) folder ||
2531 (!TNY_IS_FOLDER_STORE (parent)) ||
2532 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2535 } else if (TNY_IS_FOLDER (parent) &&
2536 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2540 } else if (TNY_IS_FOLDER (parent) &&
2541 TNY_IS_FOLDER_STORE (folder) &&
2542 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2543 TNY_FOLDER_STORE (folder))) {
2544 /* Do not move a parent into a child */
2546 } else if (TNY_IS_FOLDER_STORE (parent) &&
2547 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2548 /* Check that the new folder name is not used by any
2551 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2552 /* Check that the new folder name is not used by any
2553 special local folder */
2556 /* Create the helper */
2557 helper = g_slice_new0 (XFerFolderAsyncHelper);
2558 helper->mail_op = g_object_ref (self);
2559 helper->user_callback = user_callback;
2560 helper->user_data = user_data;
2562 /* Move/Copy folder */
2563 modest_mail_operation_notify_start (self);
2564 tny_folder_copy_async (folder,
2566 tny_folder_get_name (folder),
2569 transfer_folder_status_cb,
2575 /* Set status failed and set an error */
2576 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2577 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2578 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2581 /* Call the user callback if exists */
2583 user_callback (self, NULL, user_data);
2585 /* Notify the queue */
2586 modest_mail_operation_notify_end (self);
2590 modest_mail_operation_rename_folder (ModestMailOperation *self,
2593 XferFolderAsyncUserCallback user_callback,
2596 ModestMailOperationPrivate *priv;
2597 ModestTnyFolderRules rules;
2598 XFerFolderAsyncHelper *helper;
2600 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2601 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2602 g_return_if_fail (name);
2604 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2606 /* Get account and set it into mail_operation */
2607 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2608 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2610 /* Check folder rules */
2611 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2612 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2614 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2617 TnyFolderStore *into;
2619 into = tny_folder_get_folder_store (folder);
2621 /* Check that the new folder name is not used by any
2622 special local folder */
2623 if (new_name_valid_if_local_account (priv, into, name)) {
2624 /* Create the helper */
2625 helper = g_slice_new0 (XFerFolderAsyncHelper);
2626 helper->mail_op = g_object_ref(self);
2627 helper->user_callback = user_callback;
2628 helper->user_data = user_data;
2630 /* Rename. Camel handles folder subscription/unsubscription */
2631 modest_mail_operation_notify_start (self);
2632 tny_folder_copy_async (folder, into, name, TRUE,
2634 transfer_folder_status_cb,
2636 g_object_unref (into);
2638 g_object_unref (into);
2645 /* Set status failed and set an error */
2646 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2647 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2648 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2649 _("FIXME: unable to rename"));
2652 user_callback (self, NULL, user_data);
2654 /* Notify about operation end */
2655 modest_mail_operation_notify_end (self);
2658 /* ******************************************************************* */
2659 /* ************************** MSG ACTIONS ************************* */
2660 /* ******************************************************************* */
2663 modest_mail_operation_find_msg (ModestMailOperation *self,
2665 const gchar *msg_uid,
2666 gboolean progress_feedback,
2667 GetMsgAsyncUserCallback user_callback,
2670 GetMsgInfo *helper = NULL;
2671 ModestMailOperationPrivate *priv;
2673 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2674 g_return_if_fail (msg_uid != NULL);
2676 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2677 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2681 /* Check memory low */
2682 if (_check_memory_low (self)) {
2684 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2685 modest_mail_operation_notify_end (self);
2689 /* Get account and set it into mail_operation */
2690 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2692 /* Check for cached messages */
2693 if (progress_feedback) {
2694 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2696 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2699 /* Create the helper */
2700 helper = g_slice_new0 (GetMsgInfo);
2701 helper->header = NULL;
2702 helper->mail_op = g_object_ref (self);
2703 helper->user_callback = user_callback;
2704 helper->user_data = user_data;
2705 helper->destroy_notify = NULL;
2706 helper->last_total_bytes = 0;
2707 helper->sum_total_bytes = 0;
2708 helper->total_bytes = 0;
2709 helper->more_msgs = NULL;
2710 helper->get_parts = NULL;
2713 modest_mail_operation_notify_start (self);
2715 /* notify about the start of the operation */
2716 ModestMailOperationState *state;
2717 state = modest_mail_operation_clone_state (self);
2720 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2722 g_slice_free (ModestMailOperationState, state);
2724 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2728 modest_mail_operation_get_msg (ModestMailOperation *self,
2730 gboolean progress_feedback,
2731 GetMsgAsyncUserCallback user_callback,
2734 GetMsgInfo *helper = NULL;
2736 ModestMailOperationPrivate *priv;
2738 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2739 g_return_if_fail (TNY_IS_HEADER (header));
2741 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2742 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2746 /* Check memory low */
2747 if (_check_memory_low (self)) {
2749 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2750 modest_mail_operation_notify_end (self);
2754 /* Get account and set it into mail_operation */
2755 folder = tny_header_get_folder (header);
2756 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2758 /* Check for cached messages */
2759 if (progress_feedback) {
2760 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2761 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2763 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2765 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2768 /* Create the helper */
2769 helper = g_slice_new0 (GetMsgInfo);
2770 helper->header = g_object_ref (header);
2771 helper->mail_op = g_object_ref (self);
2772 helper->user_callback = user_callback;
2773 helper->user_data = user_data;
2774 helper->destroy_notify = NULL;
2775 helper->last_total_bytes = 0;
2776 helper->sum_total_bytes = 0;
2777 helper->total_bytes = tny_header_get_message_size (header);
2778 helper->more_msgs = NULL;
2779 helper->get_parts = NULL;
2782 modest_mail_operation_notify_start (self);
2784 /* notify about the start of the operation */
2785 ModestMailOperationState *state;
2786 state = modest_mail_operation_clone_state (self);
2789 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2791 g_slice_free (ModestMailOperationState, state);
2793 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2795 g_object_unref (G_OBJECT (folder));
2799 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2802 gboolean progress_feedback,
2803 GetMsgAsyncUserCallback user_callback,
2806 GetMsgInfo *helper = NULL;
2808 ModestMailOperationPrivate *priv;
2810 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2811 g_return_if_fail (TNY_IS_HEADER (header));
2813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2814 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2818 /* Check memory low */
2819 if (_check_memory_low (self)) {
2821 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2822 modest_mail_operation_notify_end (self);
2826 /* Get account and set it into mail_operation */
2827 folder = tny_header_get_folder (header);
2828 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2829 const gchar *acc_name;
2830 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2831 priv->account = modest_tny_account_store_get_server_account
2832 (modest_runtime_get_account_store (),
2834 TNY_ACCOUNT_TYPE_STORE);
2835 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2836 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2838 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2841 /* Check for cached messages */
2842 if (progress_feedback) {
2843 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2844 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2846 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2848 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2851 /* Create the helper */
2852 helper = g_slice_new0 (GetMsgInfo);
2853 helper->header = g_object_ref (header);
2854 helper->mail_op = g_object_ref (self);
2855 helper->user_callback = user_callback;
2856 helper->user_data = user_data;
2857 helper->destroy_notify = NULL;
2858 helper->last_total_bytes = 0;
2859 helper->sum_total_bytes = 0;
2860 helper->total_bytes = tny_header_get_message_size (header);
2861 helper->more_msgs = NULL;
2862 helper->get_parts = tny_list_create_iterator (parts);
2865 modest_mail_operation_notify_start (self);
2867 /* notify about the start of the operation */
2868 ModestMailOperationState *state;
2869 state = modest_mail_operation_clone_state (self);
2872 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2874 g_slice_free (ModestMailOperationState, state);
2876 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2878 g_object_unref (G_OBJECT (folder));
2882 get_msg_status_cb (GObject *obj,
2886 GetMsgInfo *helper = NULL;
2888 g_return_if_fail (status != NULL);
2890 /* Show only the status information we want */
2891 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2894 helper = (GetMsgInfo *) user_data;
2895 g_return_if_fail (helper != NULL);
2897 /* Notify progress */
2898 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2899 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2903 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2906 TnyFolder *folder = NULL;
2908 helper = (GetMsgInfo *) user_data;
2910 if (helper->header) {
2911 folder = tny_header_get_folder (helper->header);
2914 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2916 if (folder) g_object_unref (folder);
2920 get_msg_async_cb (TnyFolder *folder,
2926 GetMsgInfo *info = NULL;
2927 ModestMailOperationPrivate *priv = NULL;
2930 info = (GetMsgInfo *) user_data;
2932 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2935 if (info->more_msgs) {
2936 tny_iterator_next (info->more_msgs);
2937 finished = (tny_iterator_is_done (info->more_msgs));
2938 } else if (info->get_parts) {
2939 tny_iterator_next (info->get_parts);
2940 finished = (tny_iterator_is_done (info->get_parts));
2942 finished = (priv->done == priv->total) ? TRUE : FALSE;
2945 /* If canceled by the user, ignore the error given by Tinymail */
2949 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2951 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2952 priv->error = g_error_copy ((const GError *) err);
2954 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2956 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2957 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2958 "%s", err->message);
2960 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2961 /* Set the success status before calling the user callback */
2962 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2965 if (info->header == NULL && msg)
2966 info->header = tny_msg_get_header (msg);
2968 /* Call the user callback */
2969 if (info->user_callback && (finished || (info->get_parts == NULL)))
2970 info->user_callback (info->mail_op, info->header, canceled,
2971 msg, err, info->user_data);
2973 /* Notify about operation end if this is the last callback */
2975 /* Free user data */
2976 if (info->destroy_notify)
2977 info->destroy_notify (info->user_data);
2979 /* Notify about operation end */
2980 modest_mail_operation_notify_end (info->mail_op);
2984 g_object_unref (info->msg);
2985 if (info->more_msgs)
2986 g_object_unref (info->more_msgs);
2988 g_object_unref (info->header);
2989 g_object_unref (info->mail_op);
2990 g_slice_free (GetMsgInfo, info);
2991 } else if (info->get_parts) {
2992 CamelStream *null_stream;
2993 TnyStream *tny_null_stream;
2996 if (info->msg == NULL && msg != NULL)
2997 info->msg = g_object_ref (msg);
2999 null_stream = camel_stream_null_new ();
3000 tny_null_stream = tny_camel_stream_new (null_stream);
3002 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
3003 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
3004 get_msg_async_get_part_cb,
3007 g_object_unref (tny_null_stream);
3008 g_object_unref (part);
3010 } else if (info->more_msgs) {
3011 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
3012 TnyFolder *folder = tny_header_get_folder (header);
3014 g_object_unref (info->header);
3015 info->header = g_object_ref (header);
3017 /* Retrieve the next message */
3018 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
3020 g_object_unref (header);
3021 g_object_unref (folder);
3023 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
3028 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
3029 TnyList *header_list,
3030 GetMsgAsyncUserCallback user_callback,
3032 GDestroyNotify notify)
3034 ModestMailOperationPrivate *priv = NULL;
3036 TnyIterator *iter = NULL;
3037 gboolean has_uncached_messages;
3039 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3041 /* Init mail operation */
3042 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3043 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3045 priv->total = tny_list_get_length(header_list);
3047 /* Check memory low */
3048 if (_check_memory_low (self)) {
3049 if (user_callback) {
3050 TnyHeader *header = NULL;
3053 if (tny_list_get_length (header_list) > 0) {
3054 iter = tny_list_create_iterator (header_list);
3055 header = (TnyHeader *) tny_iterator_get_current (iter);
3056 g_object_unref (iter);
3058 user_callback (self, header, FALSE, NULL, priv->error, user_data);
3060 g_object_unref (header);
3064 /* Notify about operation end */
3065 modest_mail_operation_notify_end (self);
3069 /* Check uncached messages */
3070 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
3071 !has_uncached_messages && !tny_iterator_is_done (iter);
3072 tny_iterator_next (iter)) {
3075 header = (TnyHeader *) tny_iterator_get_current (iter);
3076 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
3077 has_uncached_messages = TRUE;
3078 g_object_unref (header);
3080 g_object_unref (iter);
3081 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
3083 /* Get account and set it into mail_operation */
3084 if (tny_list_get_length (header_list) >= 1) {
3085 TnyIterator *iterator = tny_list_create_iterator (header_list);
3086 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
3088 TnyFolder *folder = tny_header_get_folder (header);
3090 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3091 g_object_unref (folder);
3093 g_object_unref (header);
3095 g_object_unref (iterator);
3098 msg_list_size = compute_message_list_size (header_list, 0);
3100 modest_mail_operation_notify_start (self);
3101 iter = tny_list_create_iterator (header_list);
3102 if (!tny_iterator_is_done (iter)) {
3103 /* notify about the start of the operation */
3104 ModestMailOperationState *state;
3105 state = modest_mail_operation_clone_state (self);
3108 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3111 GetMsgInfo *msg_info = NULL;
3112 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3113 TnyFolder *folder = tny_header_get_folder (header);
3115 /* Create the message info */
3116 msg_info = g_slice_new0 (GetMsgInfo);
3117 msg_info->mail_op = g_object_ref (self);
3118 msg_info->header = g_object_ref (header);
3119 msg_info->more_msgs = g_object_ref (iter);
3120 msg_info->user_callback = user_callback;
3121 msg_info->user_data = user_data;
3122 msg_info->destroy_notify = notify;
3123 msg_info->last_total_bytes = 0;
3124 msg_info->sum_total_bytes = 0;
3125 msg_info->total_bytes = msg_list_size;
3126 msg_info->msg = NULL;
3128 /* The callback will call it per each header */
3129 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3131 /* Free and go on */
3132 g_object_unref (header);
3133 g_object_unref (folder);
3134 g_slice_free (ModestMailOperationState, state);
3136 g_object_unref (iter);
3141 remove_msgs_async_cb (TnyFolder *folder,
3147 const gchar *account_name;
3148 TnyAccount *account;
3149 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3150 ModestMailOperation *self;
3151 ModestMailOperationPrivate *priv;
3152 ModestProtocolRegistry *protocol_registry;
3153 SyncFolderHelper *helper;
3155 self = (ModestMailOperation *) user_data;
3156 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3157 protocol_registry = modest_runtime_get_protocol_registry ();
3159 if (canceled || err) {
3160 /* If canceled by the user, ignore the error given by Tinymail */
3162 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3164 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3165 priv->error = g_error_copy ((const GError *) err);
3166 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3169 modest_mail_operation_notify_end (self);
3170 g_object_unref (self);
3174 account = modest_tny_folder_get_account (folder);
3175 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3176 account_proto = modest_tny_account_get_protocol_type (account);
3177 g_object_unref (account);
3179 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3180 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3190 helper = g_slice_new0 (SyncFolderHelper);
3191 helper->mail_op = g_object_ref (self);
3192 helper->user_callback = NULL;
3193 helper->user_data = NULL;
3196 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3198 /* Remove the extra reference */
3199 g_object_unref (self);
3203 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3205 gboolean remove_to_trash /*ignored*/)
3207 TnyFolder *folder = NULL;
3208 ModestMailOperationPrivate *priv;
3209 TnyIterator *iter = NULL;
3210 TnyHeader *header = NULL;
3211 TnyList *remove_headers = NULL;
3212 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3213 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3215 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3216 g_return_if_fail (TNY_IS_LIST (headers));
3218 if (remove_to_trash)
3219 g_warning ("remove to trash is not implemented");
3221 if (tny_list_get_length(headers) == 0) {
3222 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3223 goto cleanup; /* nothing to do */
3226 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3228 /* Get folder from first header and sync it */
3229 iter = tny_list_create_iterator (headers);
3230 header = TNY_HEADER (tny_iterator_get_current (iter));
3231 g_object_unref (iter);
3233 folder = tny_header_get_folder (header);
3234 if (!TNY_IS_FOLDER(folder)) {
3235 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3239 /* Use the merged folder if we're removing messages from outbox */
3240 if (modest_tny_folder_is_local_folder (folder)) {
3241 ModestTnyLocalFoldersAccount *local_account;
3243 local_account = (ModestTnyLocalFoldersAccount *)
3244 modest_tny_account_store_get_local_folders_account (accstore);
3245 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3246 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3247 g_object_unref (folder);
3248 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3250 g_object_unref (local_account);
3253 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3254 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3256 while (!tny_iterator_is_done (headers_iter)) {
3257 TnyTransportAccount *traccount = NULL;
3258 TnyHeader *hdr = NULL;
3260 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3261 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3264 ModestTnySendQueueStatus status;
3265 ModestTnySendQueue *send_queue;
3267 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3268 if (TNY_IS_SEND_QUEUE (send_queue)) {
3271 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3272 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3273 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3274 if (G_UNLIKELY (remove_headers == NULL))
3275 remove_headers = tny_simple_list_new ();
3276 tny_list_append(remove_headers, G_OBJECT(hdr));
3280 g_object_unref(traccount);
3282 g_object_unref(hdr);
3283 tny_iterator_next (headers_iter);
3285 g_object_unref(headers_iter);
3288 /* Get account and set it into mail_operation */
3289 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3290 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3291 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3293 if (!remove_headers)
3294 remove_headers = g_object_ref (headers);
3296 /* remove message from folder */
3297 modest_mail_operation_notify_start (self);
3298 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3299 NULL, g_object_ref (self));
3303 g_object_unref (remove_headers);
3305 g_object_unref (header);
3307 g_object_unref (folder);
3311 notify_progress_of_multiple_messages (ModestMailOperation *self,
3313 gint *last_total_bytes,
3314 gint *sum_total_bytes,
3316 gboolean increment_done)
3318 ModestMailOperationPrivate *priv;
3319 ModestMailOperationState *state;
3320 gboolean is_num_bytes = FALSE;
3322 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3324 /* We know that tinymail sends us information about
3325 * transferred bytes with this particular message
3327 if (status->message)
3328 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3330 state = modest_mail_operation_clone_state (self);
3331 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3332 /* We know that we're in a different message when the
3333 total number of bytes to transfer is different. Of
3334 course it could fail if we're transferring messages
3335 of the same size, but this is a workarround */
3336 if (status->of_total != *last_total_bytes) {
3337 /* We need to increment the done when there is
3338 no information about each individual
3339 message, we need to do this in message
3340 transfers, and we don't do it for getting
3344 *sum_total_bytes += *last_total_bytes;
3345 *last_total_bytes = status->of_total;
3347 state->bytes_done += status->position + *sum_total_bytes;
3348 state->bytes_total = total_bytes;
3350 /* Notify the status change. Only notify about changes
3351 referred to bytes */
3352 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3356 g_slice_free (ModestMailOperationState, state);
3360 transfer_msgs_status_cb (GObject *obj,
3364 XFerMsgsAsyncHelper *helper;
3366 g_return_if_fail (status != NULL);
3368 /* Show only the status information we want */
3369 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3372 helper = (XFerMsgsAsyncHelper *) user_data;
3373 g_return_if_fail (helper != NULL);
3375 /* Notify progress */
3376 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3377 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3381 transfer_msgs_sync_folder_cb (TnyFolder *self,
3386 XFerMsgsAsyncHelper *helper;
3387 /* We don't care here about the results of the
3389 helper = (XFerMsgsAsyncHelper *) user_data;
3391 /* Notify about operation end */
3392 modest_mail_operation_notify_end (helper->mail_op);
3394 /* If user defined callback function was defined, call it */
3395 if (helper->user_callback)
3396 helper->user_callback (helper->mail_op, helper->user_data);
3399 if (helper->more_msgs)
3400 g_object_unref (helper->more_msgs);
3401 if (helper->headers)
3402 g_object_unref (helper->headers);
3403 if (helper->dest_folder)
3404 g_object_unref (helper->dest_folder);
3405 if (helper->mail_op)
3406 g_object_unref (helper->mail_op);
3407 g_slice_free (XFerMsgsAsyncHelper, helper);
3411 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3413 XFerMsgsAsyncHelper *helper;
3414 ModestMailOperation *self;
3415 ModestMailOperationPrivate *priv;
3416 gboolean finished = TRUE;
3418 helper = (XFerMsgsAsyncHelper *) user_data;
3419 self = helper->mail_op;
3421 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3424 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3426 priv->error = g_error_copy (err);
3428 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3429 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3430 if (helper->more_msgs) {
3431 /* We'll transfer the next message in the list */
3432 tny_iterator_next (helper->more_msgs);
3433 if (!tny_iterator_is_done (helper->more_msgs)) {
3434 GObject *next_header;
3435 g_object_unref (helper->headers);
3436 helper->headers = tny_simple_list_new ();
3437 next_header = tny_iterator_get_current (helper->more_msgs);
3438 tny_list_append (helper->headers, next_header);
3439 g_object_unref (next_header);
3445 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3450 /* Synchronize the source folder contents. This should
3451 be done by tinymail but the camel_folder_sync it's
3452 actually disabled in transfer_msgs_thread_clean
3453 because it's supposed to cause hangs */
3454 tny_folder_sync_async (folder, helper->delete,
3455 transfer_msgs_sync_folder_cb,
3458 /* Transfer more messages */
3459 tny_folder_transfer_msgs_async (folder,
3461 helper->dest_folder,
3464 transfer_msgs_status_cb,
3469 /* Computes the size of the messages the headers in the list belongs
3470 to. If num_elements is different from 0 then it only takes into
3471 account the first num_elements for the calculation */
3473 compute_message_list_size (TnyList *headers,
3477 guint size = 0, element = 0;
3479 /* If num_elements is not valid then take all into account */
3480 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3481 num_elements = tny_list_get_length (headers);
3483 iter = tny_list_create_iterator (headers);
3484 while (!tny_iterator_is_done (iter) && element < num_elements) {
3485 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3486 size += tny_header_get_message_size (header);
3487 g_object_unref (header);
3488 tny_iterator_next (iter);
3491 g_object_unref (iter);
3497 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3500 gboolean delete_original,
3501 XferMsgsAsyncUserCallback user_callback,
3504 ModestMailOperationPrivate *priv = NULL;
3505 TnyIterator *iter = NULL;
3506 TnyFolder *src_folder = NULL;
3507 XFerMsgsAsyncHelper *helper = NULL;
3508 TnyHeader *header = NULL;
3509 ModestTnyFolderRules rules = 0;
3510 TnyAccount *dst_account = NULL;
3511 gboolean leave_on_server;
3512 ModestMailOperationState *state;
3513 ModestProtocolRegistry *protocol_registry;
3514 ModestProtocolType account_protocol;
3516 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3517 g_return_if_fail (headers && TNY_IS_LIST (headers));
3518 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3520 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3521 protocol_registry = modest_runtime_get_protocol_registry ();
3523 priv->total = tny_list_get_length (headers);
3525 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3526 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3528 /* Apply folder rules */
3529 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3530 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3531 /* Set status failed and set an error */
3532 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3533 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3534 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3535 _CS("ckct_ib_unable_to_paste_here"));
3536 /* Notify the queue */
3537 modest_mail_operation_notify_end (self);
3541 /* Get source folder */
3542 iter = tny_list_create_iterator (headers);
3543 header = TNY_HEADER (tny_iterator_get_current (iter));
3545 src_folder = tny_header_get_folder (header);
3546 g_object_unref (header);
3548 g_object_unref (iter);
3550 if (src_folder == NULL) {
3551 /* Notify the queue */
3552 modest_mail_operation_notify_end (self);
3554 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3559 /* Check folder source and destination */
3560 if (src_folder == folder) {
3561 /* Set status failed and set an error */
3562 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3563 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3564 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3565 _("mail_in_ui_folder_copy_target_error"));
3567 /* Notify the queue */
3568 modest_mail_operation_notify_end (self);
3571 g_object_unref (src_folder);
3575 /* Create the helper */
3576 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3577 helper->mail_op = g_object_ref(self);
3578 helper->dest_folder = g_object_ref(folder);
3579 helper->user_callback = user_callback;
3580 helper->user_data = user_data;
3581 helper->last_total_bytes = 0;
3582 helper->sum_total_bytes = 0;
3583 helper->total_bytes = compute_message_list_size (headers, 0);
3585 /* Get account and set it into mail_operation */
3586 priv->account = modest_tny_folder_get_account (src_folder);
3587 dst_account = modest_tny_folder_get_account (folder);
3589 if (priv->account == dst_account) {
3590 /* Transfer all messages at once using the fast
3591 * method. Note that depending on the server this
3592 * might not be that fast, and might not be
3593 * user-cancellable either */
3594 helper->headers = g_object_ref (headers);
3595 helper->more_msgs = NULL;
3597 /* Transfer messages one by one so the user can cancel
3600 helper->headers = tny_simple_list_new ();
3601 helper->more_msgs = tny_list_create_iterator (headers);
3602 hdr = tny_iterator_get_current (helper->more_msgs);
3603 tny_list_append (helper->headers, hdr);
3604 g_object_unref (hdr);
3607 /* If leave_on_server is set to TRUE then don't use
3608 delete_original, we always pass FALSE. This is because
3609 otherwise tinymail will try to sync the source folder and
3610 this could cause an error if we're offline while
3611 transferring an already downloaded message from a POP
3613 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3614 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3615 const gchar *account_name;
3617 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3618 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3621 leave_on_server = FALSE;
3624 /* Do not delete messages if leave on server is TRUE */
3625 helper->delete = (leave_on_server) ? FALSE : delete_original;
3627 modest_mail_operation_notify_start (self);
3629 /* Start notifying progress */
3630 state = modest_mail_operation_clone_state (self);
3633 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3634 g_slice_free (ModestMailOperationState, state);
3636 tny_folder_transfer_msgs_async (src_folder,
3641 transfer_msgs_status_cb,
3643 g_object_unref (src_folder);
3644 g_object_unref (dst_account);
3649 on_refresh_folder (TnyFolder *folder,
3654 RefreshAsyncHelper *helper = NULL;
3655 ModestMailOperation *self = NULL;
3656 ModestMailOperationPrivate *priv = NULL;
3658 helper = (RefreshAsyncHelper *) user_data;
3659 self = helper->mail_op;
3660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3662 g_return_if_fail(priv!=NULL);
3665 priv->error = g_error_copy (error);
3666 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3671 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3672 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3673 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3674 _("Error trying to refresh the contents of %s"),
3675 tny_folder_get_name (folder));
3679 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3682 /* Call user defined callback, if it exists */
3683 if (helper->user_callback) {
3685 /* This is not a GDK lock because we are a Tinymail callback and
3686 * Tinymail already acquires the Gdk lock */
3687 helper->user_callback (self, folder, helper->user_data);
3691 g_slice_free (RefreshAsyncHelper, helper);
3693 /* Notify about operation end */
3694 modest_mail_operation_notify_end (self);
3695 g_object_unref(self);
3699 on_refresh_folder_status_update (GObject *obj,
3703 RefreshAsyncHelper *helper = NULL;
3704 ModestMailOperation *self = NULL;
3705 ModestMailOperationPrivate *priv = NULL;
3706 ModestMailOperationState *state;
3708 g_return_if_fail (user_data != NULL);
3709 g_return_if_fail (status != NULL);
3711 /* Show only the status information we want */
3712 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3715 helper = (RefreshAsyncHelper *) user_data;
3716 self = helper->mail_op;
3717 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3719 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3721 priv->done = status->position;
3722 priv->total = status->of_total;
3724 state = modest_mail_operation_clone_state (self);
3726 /* This is not a GDK lock because we are a Tinymail callback and
3727 * Tinymail already acquires the Gdk lock */
3728 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3730 g_slice_free (ModestMailOperationState, state);
3734 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3736 RefreshAsyncUserCallback user_callback,
3739 ModestMailOperationPrivate *priv = NULL;
3740 RefreshAsyncHelper *helper = NULL;
3742 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3744 /* Check memory low */
3745 if (_check_memory_low (self)) {
3747 user_callback (self, folder, user_data);
3748 /* Notify about operation end */
3749 modest_mail_operation_notify_end (self);
3753 /* Get account and set it into mail_operation */
3754 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3755 priv->account = modest_tny_folder_get_account (folder);
3756 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3758 /* Create the helper */
3759 helper = g_slice_new0 (RefreshAsyncHelper);
3760 helper->mail_op = g_object_ref(self);
3761 helper->user_callback = user_callback;
3762 helper->user_data = user_data;
3764 modest_mail_operation_notify_start (self);
3766 /* notify that the operation was started */
3767 ModestMailOperationState *state;
3768 state = modest_mail_operation_clone_state (self);
3771 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3773 g_slice_free (ModestMailOperationState, state);
3775 tny_folder_refresh_async (folder,
3777 on_refresh_folder_status_update,
3782 run_queue_notify_and_destroy (RunQueueHelper *helper,
3783 ModestMailOperationStatus status)
3785 ModestMailOperationPrivate *priv;
3788 if (helper->error_handler &&
3789 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3790 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3791 if (helper->start_handler &&
3792 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3793 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3794 if (helper->stop_handler &&
3795 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3796 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3799 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3800 priv->status = status;
3803 modest_mail_operation_notify_end (helper->self);
3806 g_object_unref (helper->queue);
3807 g_object_unref (helper->self);
3808 g_slice_free (RunQueueHelper, helper);
3812 run_queue_stop (ModestTnySendQueue *queue,
3815 RunQueueHelper *helper;
3817 g_debug ("%s sending queue stopped", __FUNCTION__);
3819 helper = (RunQueueHelper *) user_data;
3820 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3824 modest_mail_operation_run_queue (ModestMailOperation *self,
3825 ModestTnySendQueue *queue)
3827 ModestMailOperationPrivate *priv;
3828 RunQueueHelper *helper;
3830 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3831 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3832 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3834 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3835 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3836 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3838 /* Create the helper */
3839 helper = g_slice_new0 (RunQueueHelper);
3840 helper->queue = g_object_ref (queue);
3841 helper->self = g_object_ref (self);
3842 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3843 G_CALLBACK (run_queue_stop),
3846 /* Notify operation has started */
3847 modest_mail_operation_notify_start (self);
3848 g_debug ("%s, run queue started", __FUNCTION__);
3852 queue_wakeup_callback (ModestTnySendQueue *queue,
3857 ModestMailOperation *mail_op;
3858 ModestMailOperationPrivate *priv;
3860 mail_op = (ModestMailOperation *) userdata;
3861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3863 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3864 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3867 modest_mail_operation_notify_end (mail_op);
3868 g_object_unref (mail_op);
3872 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3873 ModestTnySendQueue *queue)
3875 ModestMailOperationPrivate *priv;
3877 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3878 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3879 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3881 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3882 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3883 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3885 g_object_ref (self);
3887 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3888 modest_mail_operation_notify_start (self);
3892 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3894 ModestMailOperation *self = (ModestMailOperation *) userdata;
3895 ModestMailOperationPrivate *priv;
3897 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3898 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3899 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3901 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3903 modest_mail_operation_notify_end (self);
3904 g_object_unref (self);
3908 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3910 ModestMailOperationPrivate *priv;
3912 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3913 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3914 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3916 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3918 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3919 priv->account = NULL;
3920 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3922 modest_mail_operation_notify_start (self);
3923 g_object_ref (self);
3924 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3928 sync_folder_finish_callback (TnyFolder *self,
3934 ModestMailOperationPrivate *priv;
3935 SyncFolderHelper *helper;
3937 helper = (SyncFolderHelper *) user_data;
3938 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3940 /* If canceled by the user, ignore the error given by Tinymail */
3942 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3944 /* If the operation was a sync then the status is
3945 failed, but if it's part of another operation then
3946 just set it as finished with errors */
3947 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3948 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3950 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3951 priv->error = g_error_copy ((const GError *) err);
3952 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3954 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3958 if (helper->user_callback)
3959 helper->user_callback (helper->mail_op, self, helper->user_data);
3961 modest_mail_operation_notify_end (helper->mail_op);
3964 g_object_unref (helper->mail_op);
3965 g_slice_free (SyncFolderHelper, helper);
3969 modest_mail_operation_sync_folder (ModestMailOperation *self,
3972 SyncFolderCallback callback,
3975 ModestMailOperationPrivate *priv;
3976 SyncFolderHelper *helper;
3978 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3979 g_return_if_fail (TNY_IS_FOLDER (folder));
3980 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3982 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3983 priv->account = modest_tny_folder_get_account (folder);
3984 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3987 helper = g_slice_new0 (SyncFolderHelper);
3988 helper->mail_op = g_object_ref (self);
3989 helper->user_callback = callback;
3990 helper->user_data = user_data;
3992 modest_mail_operation_notify_start (self);
3993 tny_folder_sync_async (folder, expunge,
3994 (TnyFolderCallback) sync_folder_finish_callback,
3999 modest_mail_operation_notify_start (ModestMailOperation *self)
4001 ModestMailOperationPrivate *priv = NULL;
4003 g_return_if_fail (self);
4005 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4007 /* Ensure that all the fields are filled correctly */
4008 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
4010 /* Notify the observers about the mail operation. We do not
4011 wrapp this emission because we assume that this function is
4012 always called from within the main lock */
4013 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
4018 * It's used by the mail operation queue to notify the observers
4019 * attached to that signal that the operation finished. We need to use
4020 * that because tinymail does not give us the progress of a given
4021 * operation when it finishes (it directly calls the operation
4025 modest_mail_operation_notify_end (ModestMailOperation *self)
4027 ModestMailOperationPrivate *priv = NULL;
4029 g_return_if_fail (self);
4031 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4033 /* Notify the observers about the mail operation end. We do
4034 not wrapp this emission because we assume that this
4035 function is always called from within the main lock */
4036 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
4038 /* Remove the error user data */
4039 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
4040 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
4044 modest_mail_operation_get_account (ModestMailOperation *self)
4046 ModestMailOperationPrivate *priv = NULL;
4048 g_return_val_if_fail (self, NULL);
4050 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4052 return (priv->account) ? g_object_ref (priv->account) : NULL;
4056 modest_mail_operation_noop (ModestMailOperation *self)
4058 ModestMailOperationPrivate *priv = NULL;
4060 g_return_if_fail (self);
4062 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4063 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4064 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
4068 /* This mail operation does nothing actually */
4069 modest_mail_operation_notify_start (self);
4070 modest_mail_operation_notify_end (self);
4075 modest_mail_operation_to_string (ModestMailOperation *self)
4077 const gchar *type, *status, *account_id;
4078 ModestMailOperationPrivate *priv = NULL;
4080 g_return_val_if_fail (self, NULL);
4082 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4084 /* new operations don't have anything interesting */
4085 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
4086 return g_strdup_printf ("%p <new operation>", self);
4088 switch (priv->op_type) {
4089 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
4090 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
4091 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
4092 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
4093 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
4094 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
4095 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
4096 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
4097 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
4098 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
4099 default: type = "UNEXPECTED"; break;
4102 switch (priv->status) {
4103 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4104 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4105 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4106 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4107 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4108 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4109 default: status= "UNEXPECTED"; break;
4112 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4114 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4115 priv->done, priv->total,
4116 priv->error && priv->error->message ? priv->error->message : "");
4120 * Once the mail operations were objects this will be no longer
4121 * needed. I don't like it, but we need it for the moment
4124 _check_memory_low (ModestMailOperation *mail_op)
4126 if (modest_platform_check_memory_low (NULL, FALSE)) {
4127 ModestMailOperationPrivate *priv;
4129 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4130 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4131 g_set_error (&(priv->error),
4132 MODEST_MAIL_OPERATION_ERROR,
4133 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4134 "Not enough memory to complete the operation");