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_mail (ModestMailOperation *self,
1107 TnyTransportAccount *transport_account,
1110 TnySendQueue *send_queue = NULL;
1111 ModestMailOperationPrivate *priv = NULL;
1113 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1116 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1117 modest_mail_operation_notify_end (self);
1121 if (priv->error && priv->error->code != MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1122 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1123 modest_mail_operation_notify_end (self);
1127 /* Add message to send queue */
1128 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
1129 if (!TNY_IS_SEND_QUEUE(send_queue)) {
1131 g_error_free (priv->error);
1134 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1135 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1136 "modest: could not find send queue for account\n");
1137 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1138 modest_mail_operation_notify_end (self);
1141 SendNewMailHelper *helper = g_slice_new (SendNewMailHelper);
1142 helper->mail_op = g_object_ref (self);
1143 helper->notify = TRUE;
1145 /* Add the msg to the queue. The callback will free
1147 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1149 tny_send_queue_add_async (send_queue, msg, send_mail_on_added_to_outbox,
1156 modest_mail_operation_send_new_mail (ModestMailOperation *self,
1157 TnyTransportAccount *transport_account,
1159 const gchar *from, const gchar *to,
1160 const gchar *cc, const gchar *bcc,
1161 const gchar *subject, const gchar *plain_body,
1162 const gchar *html_body,
1163 const GList *attachments_list,
1164 const GList *images_list,
1165 const gchar *references,
1166 const gchar *in_reply_to,
1167 TnyHeaderFlags priority_flags,
1168 TnyList *header_pairs)
1170 ModestMailOperationPrivate *priv = NULL;
1171 SendNewMailInfo *info;
1173 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1174 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1177 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
1178 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
1179 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1181 modest_mail_operation_notify_start (self);
1183 /* Check parametters */
1185 /* Set status failed and set an error */
1186 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1187 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1188 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
1189 _("Error trying to send a mail. You need to set at least one recipient"));
1190 modest_mail_operation_notify_end (self);
1193 info = g_slice_new0 (SendNewMailInfo);
1194 info->transport_account = transport_account;
1195 if (transport_account)
1196 g_object_ref (transport_account);
1197 info->draft_msg = draft_msg;
1199 g_object_ref (draft_msg);
1202 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1203 attachments_list, images_list, priority_flags,
1204 references, in_reply_to,
1206 modest_mail_operation_send_new_mail_cb, info);
1212 ModestMailOperation *mailop;
1214 SaveToDraftstCallback callback;
1216 } FinishSaveRemoteDraftInfo;
1219 finish_save_remote_draft (ModestAccountProtocol *protocol,
1221 const gchar *account_id,
1222 TnyMsg *new_remote_msg,
1227 FinishSaveRemoteDraftInfo *info = (FinishSaveRemoteDraftInfo *) userdata;
1228 ModestMailOperationPrivate *priv = NULL;
1230 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1232 if (!priv->error && err != NULL) {
1233 /* Priority for errors in save to local stage */
1234 priv->error = g_error_copy (err);
1235 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1239 info->callback (info->mailop, info->msg, info->userdata);
1242 g_object_unref (info->msg);
1244 modest_mail_operation_notify_end (info->mailop);
1245 g_object_unref (info->mailop);
1247 g_slice_free (FinishSaveRemoteDraftInfo, info);
1252 TnyTransportAccount *transport_account;
1254 SaveToDraftstCallback callback;
1258 ModestMailOperation *mailop;
1259 } SaveToDraftsAddMsgInfo;
1262 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
1267 ModestMailOperationPrivate *priv = NULL;
1268 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
1269 GError *io_error = NULL;
1270 gboolean callback_called = FALSE;
1272 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
1274 if (priv->error && priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1275 io_error = priv->error;
1279 g_warning ("%s: priv->error != NULL", __FUNCTION__);
1280 g_error_free(priv->error);
1283 priv->error = (err == NULL) ? NULL : g_error_copy(err);
1285 if ((!priv->error) && (info->draft_msg != NULL)) {
1286 TnyHeader *header = tny_msg_get_header (info->draft_msg);
1287 TnyFolder *src_folder = tny_header_get_folder (header);
1289 g_debug ("--- REMOVE AND SYNC");
1290 /* Remove the old draft */
1291 tny_folder_remove_msg (src_folder, header, NULL);
1293 /* Synchronize to expunge and to update the msg counts */
1294 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
1295 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
1296 g_debug ("--- REMOVED - SYNCED");
1298 g_object_unref (G_OBJECT(header));
1299 g_object_unref (G_OBJECT(src_folder));
1303 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1305 g_error_free (io_error);
1308 } else if (io_error) {
1309 priv->error = io_error;
1310 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
1312 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1315 if (info->transport_account) {
1316 ModestProtocolType transport_protocol_type;
1317 ModestProtocol *transport_protocol;
1319 transport_protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (info->transport_account));
1321 transport_protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1322 transport_protocol_type);
1323 if (transport_protocol && MODEST_IS_ACCOUNT_PROTOCOL (transport_protocol)) {
1324 FinishSaveRemoteDraftInfo *srd_info = g_slice_new (FinishSaveRemoteDraftInfo);
1325 srd_info->mailop = info->mailop?g_object_ref (info->mailop):NULL;
1326 srd_info->msg = info->msg?g_object_ref (info->msg):NULL;
1327 srd_info->callback = info->callback;
1328 srd_info->userdata = info->user_data;
1329 modest_account_protocol_save_remote_draft (MODEST_ACCOUNT_PROTOCOL (transport_protocol),
1330 tny_account_get_id (TNY_ACCOUNT (info->transport_account)),
1331 info->msg, info->draft_msg,
1332 finish_save_remote_draft,
1335 callback_called = TRUE;
1339 /* Call the user callback */
1340 if (!callback_called && info->callback)
1341 info->callback (info->mailop, info->msg, info->user_data);
1343 if (info->transport_account)
1344 g_object_unref (G_OBJECT(info->transport_account));
1345 if (info->draft_msg)
1346 g_object_unref (G_OBJECT (info->draft_msg));
1348 g_object_unref (G_OBJECT(info->drafts));
1350 g_object_unref (G_OBJECT (info->msg));
1352 if (!callback_called)
1353 modest_mail_operation_notify_end (info->mailop);
1355 g_object_unref(info->mailop);
1356 g_slice_free (SaveToDraftsAddMsgInfo, info);
1361 TnyTransportAccount *transport_account;
1363 SaveToDraftstCallback callback;
1368 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
1372 TnyFolder *drafts = NULL;
1373 ModestMailOperationPrivate *priv = NULL;
1374 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
1376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1379 if (!(priv->error)) {
1380 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1381 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1382 "modest: failed to create a new msg\n");
1385 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1386 TNY_FOLDER_TYPE_DRAFTS);
1387 if (!drafts && !(priv->error)) {
1388 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1389 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1390 "modest: failed to create a new msg\n");
1394 if (!priv->error || priv->error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1396 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1397 cb_info->transport_account = g_object_ref(info->transport_account);
1398 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1399 cb_info->callback = info->callback;
1400 cb_info->user_data = info->user_data;
1401 cb_info->drafts = g_object_ref(drafts);
1402 cb_info->msg = g_object_ref(msg);
1403 cb_info->mailop = g_object_ref(self);
1404 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1408 /* Call the user callback */
1409 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1411 info->callback (self, msg, info->user_data);
1412 modest_mail_operation_notify_end (self);
1416 g_object_unref (G_OBJECT(drafts));
1417 if (info->draft_msg)
1418 g_object_unref (G_OBJECT (info->draft_msg));
1419 if (info->transport_account)
1420 g_object_unref (G_OBJECT(info->transport_account));
1421 g_slice_free (SaveToDraftsInfo, info);
1425 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1426 TnyTransportAccount *transport_account,
1428 const gchar *from, const gchar *to,
1429 const gchar *cc, const gchar *bcc,
1430 const gchar *subject, const gchar *plain_body,
1431 const gchar *html_body,
1432 const GList *attachments_list,
1433 const GList *images_list,
1434 TnyHeaderFlags priority_flags,
1435 const gchar *references,
1436 const gchar *in_reply_to,
1437 TnyList *header_pairs,
1438 SaveToDraftstCallback callback,
1441 ModestMailOperationPrivate *priv = NULL;
1442 SaveToDraftsInfo *info = NULL;
1444 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1445 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1447 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1449 /* Get account and set it into mail_operation */
1450 priv->account = g_object_ref (transport_account);
1451 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1453 info = g_slice_new0 (SaveToDraftsInfo);
1454 info->transport_account = g_object_ref (transport_account);
1455 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1456 info->callback = callback;
1457 info->user_data = user_data;
1459 g_debug ("--- CREATE MESSAGE");
1460 modest_mail_operation_notify_start (self);
1461 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1462 attachments_list, images_list, priority_flags,
1463 references, in_reply_to,
1465 modest_mail_operation_save_to_drafts_cb, info);
1470 ModestMailOperation *mail_op;
1471 TnyMimePart *mime_part;
1473 GetMimePartSizeCallback callback;
1475 } GetMimePartSizeInfo;
1477 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1478 /* We use this folder observer to track the headers that have been
1479 * added to a folder */
1482 TnyList *new_headers;
1483 } InternalFolderObserver;
1486 GObjectClass parent;
1487 } InternalFolderObserverClass;
1489 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1491 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1492 internal_folder_observer,
1494 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1498 foreach_add_item (gpointer header, gpointer user_data)
1500 tny_list_append (TNY_LIST (user_data), G_OBJECT (header));
1503 /* This is the method that looks for new messages in a folder */
1505 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1507 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1509 TnyFolderChangeChanged changed;
1511 changed = tny_folder_change_get_changed (change);
1513 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1516 /* Get added headers */
1517 list = tny_simple_list_new ();
1518 tny_folder_change_get_added_headers (change, list);
1520 /* Add them to the folder observer */
1521 tny_list_foreach (list, foreach_add_item,
1522 derived->new_headers);
1524 g_object_unref (G_OBJECT (list));
1529 internal_folder_observer_init (InternalFolderObserver *self)
1531 self->new_headers = tny_simple_list_new ();
1534 internal_folder_observer_finalize (GObject *object)
1536 InternalFolderObserver *self;
1538 self = (InternalFolderObserver *) object;
1539 g_object_unref (self->new_headers);
1541 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1544 tny_folder_observer_init (TnyFolderObserverIface *iface)
1546 iface->update = internal_folder_observer_update;
1549 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1551 GObjectClass *object_class;
1553 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1554 object_class = (GObjectClass*) klass;
1555 object_class->finalize = internal_folder_observer_finalize;
1559 destroy_update_account_info (UpdateAccountInfo *info)
1561 g_free (info->account_name);
1562 g_object_unref (info->folders);
1563 g_object_unref (info->mail_op);
1564 g_slice_free (UpdateAccountInfo, info);
1569 update_account_send_mail (UpdateAccountInfo *info)
1571 TnyTransportAccount *transport_account = NULL;
1572 ModestTnyAccountStore *account_store;
1574 if (info->update_folder_counts)
1577 account_store = modest_runtime_get_account_store ();
1579 /* We don't try to send messages while sending mails is blocked */
1580 if (modest_tny_account_store_is_send_mail_blocked (account_store))
1583 /* Get the transport account */
1584 transport_account = (TnyTransportAccount *)
1585 modest_tny_account_store_get_server_account (account_store, info->account_name,
1586 TNY_ACCOUNT_TYPE_TRANSPORT);
1588 if (transport_account) {
1589 ModestTnySendQueue *send_queue;
1593 send_queue = modest_runtime_get_send_queue (transport_account, TRUE);
1594 g_object_unref (transport_account);
1596 if (TNY_IS_SEND_QUEUE (send_queue)) {
1597 /* Get outbox folder */
1598 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1599 if (outbox) { /* this could fail in some cases */
1600 num_messages = tny_folder_get_all_count (outbox);
1601 g_object_unref (outbox);
1603 g_warning ("%s: could not get outbox", __FUNCTION__);
1607 if (num_messages != 0) {
1608 ModestMailOperation *mail_op;
1609 /* Reenable suspended items */
1610 mail_op = modest_mail_operation_new (NULL);
1611 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1613 modest_mail_operation_queue_wakeup (mail_op, MODEST_TNY_SEND_QUEUE (send_queue));
1616 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1624 update_account_get_msg_async_cb (TnyFolder *folder,
1630 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1631 ModestMailOperationPrivate *priv;
1633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (msg_info->mail_op);
1636 if (TNY_IS_MSG (msg)) {
1637 TnyHeader *header = tny_msg_get_header (msg);
1640 ModestMailOperationState *state;
1641 state = modest_mail_operation_clone_state (msg_info->mail_op);
1642 msg_info->sum_total_bytes += tny_header_get_message_size (header);
1643 state->bytes_done = msg_info->sum_total_bytes;
1644 state->bytes_total = msg_info->total_bytes;
1646 /* Notify the status change. Only notify about changes
1647 referred to bytes */
1648 g_signal_emit (G_OBJECT (msg_info->mail_op),
1649 signals[PROGRESS_CHANGED_SIGNAL],
1652 g_object_unref (header);
1653 g_slice_free (ModestMailOperationState, state);
1657 if (priv->done == priv->total) {
1658 TnyList *new_headers;
1659 UpdateAccountInfo *info;
1661 /* After getting all the messages send the ones in the
1663 info = (UpdateAccountInfo *) msg_info->user_data;
1664 update_account_send_mail (info);
1666 /* Check if the operation was a success */
1668 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1670 /* Call the user callback and free */
1671 new_headers = tny_iterator_get_list (msg_info->more_msgs);
1672 update_account_notify_user_and_free (info, new_headers);
1674 /* Delete the helper */
1676 g_object_unref (msg_info->msg);
1677 g_object_unref (msg_info->more_msgs);
1678 g_object_unref (msg_info->mail_op);
1679 g_slice_free (GetMsgInfo, msg_info);
1684 update_account_notify_user_and_free (UpdateAccountInfo *info,
1685 TnyList *new_headers)
1687 /* Set the account back to not busy */
1688 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1689 info->account_name, FALSE);
1693 info->callback (info->mail_op, new_headers, info->user_data);
1695 /* Mail operation end */
1696 modest_mail_operation_notify_end (info->mail_op);
1700 g_object_unref (new_headers);
1701 destroy_update_account_info (info);
1705 inbox_refreshed_cb (TnyFolder *inbox,
1710 UpdateAccountInfo *info;
1711 ModestMailOperationPrivate *priv;
1712 TnyIterator *new_headers_iter;
1713 GPtrArray *new_headers_array = NULL;
1714 gint max_size = G_MAXINT, retrieve_limit, i;
1715 ModestAccountMgr *mgr;
1716 ModestAccountRetrieveType retrieve_type;
1717 TnyList *new_headers = NULL;
1718 gboolean headers_only;
1719 time_t time_to_store;
1721 info = (UpdateAccountInfo *) user_data;
1722 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1723 mgr = modest_runtime_get_account_mgr ();
1725 if (canceled || err) {
1726 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1728 priv->error = g_error_copy (err);
1730 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1731 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1735 tny_folder_remove_observer (inbox, info->inbox_observer);
1736 g_object_unref (info->inbox_observer);
1737 info->inbox_observer = NULL;
1739 /* Notify the user about the error and then exit */
1740 update_account_notify_user_and_free (info, NULL);
1745 /* Try to send anyway */
1749 if (!info->update_folder_counts) {
1750 /* Set the last updated as the current time */
1751 #ifdef MODEST_USE_LIBTIME
1753 time_get_utc (&utc_tm);
1754 time_to_store = time_mktime (&utc_tm, "GMT");
1756 time_to_store = time (NULL);
1758 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time_to_store);
1760 /* Get the message max size */
1761 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1762 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1764 max_size = G_MAXINT;
1766 max_size = max_size * KB;
1769 /* Create the new headers array. We need it to sort the
1770 new headers by date */
1771 new_headers_array = g_ptr_array_new ();
1772 if (info->inbox_observer) {
1773 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1774 if (!tny_iterator_is_done (new_headers_iter)) {
1775 modest_platform_emit_folder_updated_signal (info->account_name, tny_folder_get_id (TNY_FOLDER (inbox)));
1777 while (!tny_iterator_is_done (new_headers_iter)) {
1778 TnyHeader *header = NULL;
1780 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1781 /* Apply per-message size limits */
1782 if (tny_header_get_message_size (header) < max_size)
1783 g_ptr_array_add (new_headers_array, g_object_ref (header));
1785 g_object_unref (header);
1786 tny_iterator_next (new_headers_iter);
1788 g_object_unref (new_headers_iter);
1790 tny_folder_remove_observer (inbox, info->inbox_observer);
1791 g_object_unref (info->inbox_observer);
1792 info->inbox_observer = NULL;
1795 if (new_headers_array->len == 0) {
1796 g_ptr_array_free (new_headers_array, FALSE);
1800 /* Get per-account message amount retrieval limit */
1801 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1802 if (retrieve_limit == 0)
1803 retrieve_limit = G_MAXINT;
1805 /* Get per-account retrieval type */
1806 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1807 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1810 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1812 /* Copy the headers to a list and free the array */
1813 new_headers = tny_simple_list_new ();
1814 for (i=0; i < new_headers_array->len; i++) {
1815 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1816 /* We want the first element to be the most recent
1817 one, that's why we reverse the list */
1818 tny_list_prepend (new_headers, G_OBJECT (header));
1820 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1821 g_ptr_array_free (new_headers_array, FALSE);
1823 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1826 GetMsgInfo *msg_info;
1829 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1831 iter = tny_list_create_iterator (new_headers);
1833 /* Create the message info */
1834 msg_info = g_slice_new0 (GetMsgInfo);
1835 msg_info->mail_op = g_object_ref (info->mail_op);
1836 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1837 msg_info->more_msgs = g_object_ref (iter);
1838 msg_info->msg = NULL;
1839 msg_info->user_data = info;
1841 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1842 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1843 TnyFolder *folder = tny_header_get_folder (header);
1845 /* Get message in an async way */
1846 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1849 g_object_unref (folder);
1850 g_object_unref (header);
1853 tny_iterator_next (iter);
1855 g_object_unref (iter);
1856 g_object_unref (new_headers);
1858 /* The mail operation will finish when the last
1859 message is retrieved */
1863 /* If we don't have to retrieve the new messages then
1865 update_account_send_mail (info);
1867 /* Check if the operation was a success */
1869 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1871 /* Call the user callback and free */
1872 update_account_notify_user_and_free (info, new_headers);
1876 inbox_refresh_status_update (GObject *obj,
1880 UpdateAccountInfo *info = NULL;
1881 ModestMailOperation *self = NULL;
1882 ModestMailOperationPrivate *priv = NULL;
1883 ModestMailOperationState *state;
1885 g_return_if_fail (user_data != NULL);
1886 g_return_if_fail (status != NULL);
1888 /* Show only the status information we want */
1889 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1892 info = (UpdateAccountInfo *) user_data;
1893 self = info->mail_op;
1894 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1896 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1898 priv->done = status->position;
1899 priv->total = status->of_total;
1901 state = modest_mail_operation_clone_state (self);
1903 /* This is not a GDK lock because we are a Tinymail callback and
1904 * Tinymail already acquires the Gdk lock */
1905 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1907 g_slice_free (ModestMailOperationState, state);
1911 recurse_folders_async_cb (TnyFolderStore *folder_store,
1917 UpdateAccountInfo *info;
1918 ModestMailOperationPrivate *priv;
1920 info = (UpdateAccountInfo *) user_data;
1921 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1923 if (err || canceled) {
1924 /* If the error was previosly set by another callback
1925 don't set it again */
1927 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1929 priv->error = g_error_copy (err);
1931 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1932 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1936 /* We're not getting INBOX children if we don't want to poke all */
1937 TnyIterator *iter = tny_list_create_iterator (list);
1938 while (!tny_iterator_is_done (iter)) {
1939 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1941 /* Add to the list of all folders */
1942 tny_list_append (info->folders, (GObject *) folder);
1944 if (info->poke_all) {
1945 TnyList *folders = tny_simple_list_new ();
1946 /* Add pending call */
1947 info->pending_calls++;
1949 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1950 recurse_folders_async_cb,
1952 g_object_unref (folders);
1955 g_object_unref (G_OBJECT (folder));
1957 tny_iterator_next (iter);
1959 g_object_unref (G_OBJECT (iter));
1962 /* Remove my own pending call */
1963 info->pending_calls--;
1965 /* This means that we have all the folders */
1966 if (info->pending_calls == 0) {
1967 TnyIterator *iter_all_folders;
1968 TnyFolder *inbox = NULL;
1970 /* If there was any error do not continue */
1972 update_account_notify_user_and_free (info, NULL);
1976 iter_all_folders = tny_list_create_iterator (info->folders);
1978 /* Do a poke status over all folders */
1979 while (!tny_iterator_is_done (iter_all_folders) &&
1980 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1981 TnyFolder *folder = NULL;
1983 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1985 if (!info->update_folder_counts && tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1986 /* Get a reference to the INBOX */
1987 inbox = g_object_ref (folder);
1989 /* Issue a poke status over the folder */
1991 tny_folder_poke_status (folder);
1994 /* Free and go to next */
1995 g_object_unref (folder);
1996 tny_iterator_next (iter_all_folders);
1998 g_object_unref (iter_all_folders);
2000 /* Refresh the INBOX */
2002 /* Refresh the folder. Our observer receives
2003 * the new emails during folder refreshes, so
2004 * we can use observer->new_headers
2006 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
2007 tny_folder_add_observer (inbox, info->inbox_observer);
2009 /* Refresh the INBOX */
2010 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
2011 g_object_unref (inbox);
2013 /* We could not perform the inbox refresh but
2014 we'll try to send mails anyway */
2015 inbox_refreshed_cb (inbox, FALSE, NULL, info);
2021 modest_mail_operation_update_account (ModestMailOperation *self,
2022 const gchar *account_name,
2024 gboolean interactive,
2025 UpdateAccountCallback callback,
2028 UpdateAccountInfo *info = NULL;
2029 ModestMailOperationPrivate *priv = NULL;
2030 ModestTnyAccountStore *account_store = NULL;
2032 ModestMailOperationState *state;
2034 /* Init mail operation */
2035 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2038 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2039 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
2041 /* Get the store account */
2042 account_store = modest_runtime_get_account_store ();
2044 modest_tny_account_store_get_server_account (account_store,
2046 TNY_ACCOUNT_TYPE_STORE);
2048 /* The above function could return NULL */
2049 if (!priv->account) {
2050 /* Check if the operation was a success */
2051 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2052 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2054 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2056 /* Call the user callback */
2058 callback (self, NULL, user_data);
2060 /* Notify about operation end */
2061 modest_mail_operation_notify_end (self);
2066 /* We have once seen priv->account getting finalized during this code,
2067 * therefore adding a reference (bug #82296) */
2069 g_object_ref (priv->account);
2071 /* Create the helper object */
2072 info = g_slice_new0 (UpdateAccountInfo);
2073 info->pending_calls = 1;
2074 info->folders = tny_simple_list_new ();
2075 info->mail_op = g_object_ref (self);
2076 info->poke_all = poke_all;
2077 info->interactive = interactive;
2078 info->update_folder_counts = FALSE;
2079 info->account_name = g_strdup (account_name);
2080 info->callback = callback;
2081 info->user_data = user_data;
2083 /* Set account busy */
2084 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2085 modest_mail_operation_notify_start (self);
2087 /* notify about the start of the operation */
2088 state = modest_mail_operation_clone_state (self);
2092 /* Start notifying progress */
2093 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2094 g_slice_free (ModestMailOperationState, state);
2096 /* Get all folders and continue in the callback */
2097 folders = tny_simple_list_new ();
2098 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2099 folders, NULL, TRUE,
2100 recurse_folders_async_cb,
2102 g_object_unref (folders);
2104 g_object_unref (priv->account);
2109 modest_mail_operation_update_folder_counts (ModestMailOperation *self,
2110 const gchar *account_name)
2112 UpdateAccountInfo *info = NULL;
2113 ModestMailOperationPrivate *priv = NULL;
2114 ModestTnyAccountStore *account_store = NULL;
2116 ModestMailOperationState *state;
2118 /* Init mail operation */
2119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2122 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2123 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UPDATE_FOLDER_COUNTS;
2125 /* Get the store account */
2126 account_store = modest_runtime_get_account_store ();
2128 modest_tny_account_store_get_server_account (account_store,
2130 TNY_ACCOUNT_TYPE_STORE);
2132 /* The above function could return NULL */
2133 if (!priv->account) {
2134 /* Check if the operation was a success */
2135 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2136 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2138 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2140 /* Notify about operation end */
2141 modest_mail_operation_notify_end (self);
2146 /* We have once seen priv->account getting finalized during this code,
2147 * therefore adding a reference (bug #82296) */
2149 g_object_ref (priv->account);
2151 /* Create the helper object */
2152 info = g_slice_new0 (UpdateAccountInfo);
2153 info->pending_calls = 1;
2154 info->folders = tny_simple_list_new ();
2155 info->mail_op = g_object_ref (self);
2156 info->poke_all = TRUE;
2157 info->interactive = FALSE;
2158 info->update_folder_counts = TRUE;
2159 info->account_name = g_strdup (account_name);
2160 info->callback = NULL;
2161 info->user_data = NULL;
2163 /* Set account busy */
2164 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2165 modest_mail_operation_notify_start (self);
2167 /* notify about the start of the operation */
2168 state = modest_mail_operation_clone_state (self);
2172 /* Start notifying progress */
2173 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2174 g_slice_free (ModestMailOperationState, state);
2176 /* Get all folders and continue in the callback */
2177 folders = tny_simple_list_new ();
2178 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2179 folders, NULL, TRUE,
2180 recurse_folders_async_cb,
2182 g_object_unref (folders);
2184 g_object_unref (priv->account);
2189 * Used to notify the queue from the main
2190 * loop. We call it inside an idle call to achieve that
2193 idle_notify_queue (gpointer data)
2195 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2197 gdk_threads_enter ();
2198 modest_mail_operation_notify_end (mail_op);
2199 gdk_threads_leave ();
2200 g_object_unref (mail_op);
2206 compare_headers_by_date (gconstpointer a,
2209 TnyHeader **header1, **header2;
2210 time_t sent1, sent2;
2212 header1 = (TnyHeader **) a;
2213 header2 = (TnyHeader **) b;
2215 sent1 = tny_header_get_date_sent (*header1);
2216 sent2 = tny_header_get_date_sent (*header2);
2218 /* We want the most recent ones (greater time_t) at the
2227 /* ******************************************************************* */
2228 /* ************************** STORE ACTIONS ************************* */
2229 /* ******************************************************************* */
2232 ModestMailOperation *mail_op;
2233 CreateFolderUserCallback callback;
2239 create_folder_cb (TnyFolderStore *parent_folder,
2241 TnyFolder *new_folder,
2245 ModestMailOperationPrivate *priv;
2246 CreateFolderInfo *info;
2248 info = (CreateFolderInfo *) user_data;
2249 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2251 if (canceled || err) {
2252 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2254 priv->error = g_error_copy (err);
2256 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2257 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2260 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2263 /* The user will unref the new_folder */
2265 info->callback (info->mail_op, parent_folder,
2266 new_folder, info->user_data);
2268 /* Notify about operation end */
2269 modest_mail_operation_notify_end (info->mail_op);
2272 g_object_unref (info->mail_op);
2273 g_slice_free (CreateFolderInfo, info);
2277 modest_mail_operation_create_folder (ModestMailOperation *self,
2278 TnyFolderStore *parent,
2280 CreateFolderUserCallback callback,
2283 ModestMailOperationPrivate *priv;
2285 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2286 g_return_if_fail (name);
2288 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2289 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2290 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2291 g_object_ref (parent) :
2292 modest_tny_folder_get_account (TNY_FOLDER (parent));
2294 /* Check for already existing folder */
2295 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2296 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2297 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2298 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2299 _CS_FOLDER_ALREADY_EXISTS);
2303 if (TNY_IS_FOLDER (parent)) {
2304 /* Check folder rules */
2305 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2306 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2307 /* Set status failed and set an error */
2308 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2309 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2310 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2311 _("mail_in_ui_folder_create_error"));
2315 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2316 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2318 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2319 _("mail_in_ui_folder_create_error"));
2323 CreateFolderInfo *info;
2325 info = g_slice_new0 (CreateFolderInfo);
2326 info->mail_op = g_object_ref (self);
2327 info->callback = callback;
2328 info->user_data = user_data;
2330 modest_mail_operation_notify_start (self);
2332 /* Create the folder */
2333 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2336 /* Call the user callback anyway */
2338 callback (self, parent, NULL, user_data);
2339 /* Notify about operation end */
2340 modest_mail_operation_notify_end (self);
2345 modest_mail_operation_remove_folder (ModestMailOperation *self,
2347 gboolean remove_to_trash)
2349 ModestMailOperationPrivate *priv;
2350 ModestTnyFolderRules rules;
2352 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2353 g_return_if_fail (TNY_IS_FOLDER (folder));
2355 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2357 /* Check folder rules */
2358 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2359 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2360 /* Set status failed and set an error */
2361 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2362 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2363 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2364 _("mail_in_ui_folder_delete_error"));
2368 /* Get the account */
2369 priv->account = modest_tny_folder_get_account (folder);
2370 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2372 /* Delete folder or move to trash */
2373 if (remove_to_trash) {
2374 TnyFolder *trash_folder = NULL;
2375 trash_folder = modest_tny_account_get_special_folder (priv->account,
2376 TNY_FOLDER_TYPE_TRASH);
2377 /* TODO: error_handling */
2379 modest_mail_operation_notify_start (self);
2380 modest_mail_operation_xfer_folder (self, folder,
2381 TNY_FOLDER_STORE (trash_folder),
2383 g_object_unref (trash_folder);
2385 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2388 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2390 modest_mail_operation_notify_start (self);
2391 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2392 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2395 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2397 g_object_unref (parent);
2399 g_warning ("%s: could not get parent folder", __FUNCTION__);
2403 /* Notify about operation end */
2404 modest_mail_operation_notify_end (self);
2408 transfer_folder_status_cb (GObject *obj,
2412 ModestMailOperation *self;
2413 ModestMailOperationPrivate *priv;
2414 ModestMailOperationState *state;
2415 XFerFolderAsyncHelper *helper;
2417 g_return_if_fail (status != NULL);
2419 /* Show only the status information we want */
2420 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2423 helper = (XFerFolderAsyncHelper *) user_data;
2424 g_return_if_fail (helper != NULL);
2426 self = helper->mail_op;
2427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2429 priv->done = status->position;
2430 priv->total = status->of_total;
2432 state = modest_mail_operation_clone_state (self);
2434 /* This is not a GDK lock because we are a Tinymail callback
2435 * which is already GDK locked by Tinymail */
2437 /* no gdk_threads_enter (), CHECKED */
2439 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2441 /* no gdk_threads_leave (), CHECKED */
2443 g_slice_free (ModestMailOperationState, state);
2447 transfer_folder_cb (TnyFolder *folder,
2449 TnyFolderStore *into,
2450 TnyFolder *new_folder,
2454 XFerFolderAsyncHelper *helper;
2455 ModestMailOperation *self = NULL;
2456 ModestMailOperationPrivate *priv = NULL;
2458 helper = (XFerFolderAsyncHelper *) user_data;
2459 g_return_if_fail (helper != NULL);
2461 self = helper->mail_op;
2462 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2465 priv->error = g_error_copy (err);
2467 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2468 } else if (cancelled) {
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2470 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2471 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2472 _("Transference of %s was cancelled."),
2473 tny_folder_get_name (folder));
2476 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2479 /* Update state of new folder */
2481 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2482 tny_folder_poke_status (new_folder);
2485 /* Notify about operation end */
2486 modest_mail_operation_notify_end (self);
2488 /* If user defined callback function was defined, call it */
2489 if (helper->user_callback) {
2491 /* This is not a GDK lock because we are a Tinymail callback
2492 * which is already GDK locked by Tinymail */
2494 /* no gdk_threads_enter (), CHECKED */
2495 helper->user_callback (self, new_folder, helper->user_data);
2496 /* no gdk_threads_leave () , CHECKED */
2500 g_object_unref (helper->mail_op);
2501 g_slice_free (XFerFolderAsyncHelper, helper);
2506 * This function checks if the new name is a valid name for our local
2507 * folders account. The new name could not be the same than then name
2508 * of any of the mandatory local folders
2510 * We can not rely on tinymail because tinymail does not check the
2511 * name of the virtual folders that the account could have in the case
2512 * that we're doing a rename (because it directly calls Camel which
2513 * knows nothing about our virtual folders).
2515 * In the case of an actual copy/move (i.e. move/copy a folder between
2516 * accounts) tinymail uses the tny_folder_store_create_account which
2517 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2518 * checks the new name of the folder, so this call in that case
2519 * wouldn't be needed. *But* NOTE that if tinymail changes its
2520 * implementation (if folder transfers within the same account is no
2521 * longer implemented as a rename) this call will allow Modest to work
2524 * If the new name is not valid, this function will set the status to
2525 * failed and will set also an error in the mail operation
2528 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2529 TnyFolderStore *into,
2530 const gchar *new_name)
2532 if (TNY_IS_ACCOUNT (into) &&
2533 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2534 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2536 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2537 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2538 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2539 _CS_FOLDER_ALREADY_EXISTS);
2546 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2548 TnyFolderStore *parent,
2549 gboolean delete_original,
2550 XferFolderAsyncUserCallback user_callback,
2553 ModestMailOperationPrivate *priv = NULL;
2554 ModestTnyFolderRules parent_rules = 0, rules;
2555 XFerFolderAsyncHelper *helper = NULL;
2556 const gchar *folder_name = NULL;
2557 const gchar *error_msg;
2559 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2560 g_return_if_fail (TNY_IS_FOLDER (folder));
2561 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2563 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2564 folder_name = tny_folder_get_name (folder);
2566 /* Set the error msg */
2567 error_msg = _("mail_in_ui_folder_move_target_error");
2569 /* Get account and set it into mail_operation */
2570 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2571 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2572 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2574 /* Get folder rules */
2575 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2576 if (TNY_IS_FOLDER (parent))
2577 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2579 /* Apply operation constraints */
2580 if ((gpointer) parent == (gpointer) folder ||
2581 (!TNY_IS_FOLDER_STORE (parent)) ||
2582 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2585 } else if (TNY_IS_FOLDER (parent) &&
2586 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2590 } else if (TNY_IS_FOLDER (parent) &&
2591 TNY_IS_FOLDER_STORE (folder) &&
2592 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2593 TNY_FOLDER_STORE (folder))) {
2594 /* Do not move a parent into a child */
2596 } else if (TNY_IS_FOLDER_STORE (parent) &&
2597 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2598 /* Check that the new folder name is not used by any
2601 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2602 /* Check that the new folder name is not used by any
2603 special local folder */
2606 /* Create the helper */
2607 helper = g_slice_new0 (XFerFolderAsyncHelper);
2608 helper->mail_op = g_object_ref (self);
2609 helper->user_callback = user_callback;
2610 helper->user_data = user_data;
2612 /* Move/Copy folder */
2613 modest_mail_operation_notify_start (self);
2614 tny_folder_copy_async (folder,
2616 tny_folder_get_name (folder),
2619 transfer_folder_status_cb,
2625 /* Set status failed and set an error */
2626 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2627 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2628 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2631 /* Call the user callback if exists */
2633 user_callback (self, NULL, user_data);
2635 /* Notify the queue */
2636 modest_mail_operation_notify_end (self);
2640 modest_mail_operation_rename_folder (ModestMailOperation *self,
2643 XferFolderAsyncUserCallback user_callback,
2646 ModestMailOperationPrivate *priv;
2647 ModestTnyFolderRules rules;
2648 XFerFolderAsyncHelper *helper;
2650 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2651 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2652 g_return_if_fail (name);
2654 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2656 /* Get account and set it into mail_operation */
2657 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2658 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2660 /* Check folder rules */
2661 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2662 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2664 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2667 TnyFolderStore *into;
2669 into = tny_folder_get_folder_store (folder);
2671 /* Check that the new folder name is not used by any
2672 special local folder */
2673 if (new_name_valid_if_local_account (priv, into, name)) {
2674 /* Create the helper */
2675 helper = g_slice_new0 (XFerFolderAsyncHelper);
2676 helper->mail_op = g_object_ref(self);
2677 helper->user_callback = user_callback;
2678 helper->user_data = user_data;
2680 /* Rename. Camel handles folder subscription/unsubscription */
2681 modest_mail_operation_notify_start (self);
2682 tny_folder_copy_async (folder, into, name, TRUE,
2684 transfer_folder_status_cb,
2686 g_object_unref (into);
2688 g_object_unref (into);
2695 /* Set status failed and set an error */
2696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2698 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2699 _("FIXME: unable to rename"));
2702 user_callback (self, NULL, user_data);
2704 /* Notify about operation end */
2705 modest_mail_operation_notify_end (self);
2708 /* ******************************************************************* */
2709 /* ************************** MSG ACTIONS ************************* */
2710 /* ******************************************************************* */
2713 modest_mail_operation_find_msg (ModestMailOperation *self,
2715 const gchar *msg_uid,
2716 gboolean progress_feedback,
2717 GetMsgAsyncUserCallback user_callback,
2720 GetMsgInfo *helper = NULL;
2721 ModestMailOperationPrivate *priv;
2723 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2724 g_return_if_fail (msg_uid != NULL);
2726 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2727 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2731 /* Check memory low */
2732 if (_check_memory_low (self)) {
2734 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2735 modest_mail_operation_notify_end (self);
2739 /* Get account and set it into mail_operation */
2740 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2742 /* Check for cached messages */
2743 if (progress_feedback) {
2744 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2746 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2749 /* Create the helper */
2750 helper = g_slice_new0 (GetMsgInfo);
2751 helper->header = NULL;
2752 helper->mail_op = g_object_ref (self);
2753 helper->user_callback = user_callback;
2754 helper->user_data = user_data;
2755 helper->destroy_notify = NULL;
2756 helper->last_total_bytes = 0;
2757 helper->sum_total_bytes = 0;
2758 helper->total_bytes = 0;
2759 helper->more_msgs = NULL;
2760 helper->get_parts = NULL;
2763 modest_mail_operation_notify_start (self);
2765 /* notify about the start of the operation */
2766 ModestMailOperationState *state;
2767 state = modest_mail_operation_clone_state (self);
2770 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2772 g_slice_free (ModestMailOperationState, state);
2774 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2778 modest_mail_operation_get_msg (ModestMailOperation *self,
2780 gboolean progress_feedback,
2781 GetMsgAsyncUserCallback user_callback,
2784 GetMsgInfo *helper = NULL;
2786 ModestMailOperationPrivate *priv;
2788 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2789 g_return_if_fail (TNY_IS_HEADER (header));
2791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2792 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2796 /* Check memory low */
2797 if (_check_memory_low (self)) {
2799 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2800 modest_mail_operation_notify_end (self);
2804 /* Get account and set it into mail_operation */
2805 folder = tny_header_get_folder (header);
2806 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2808 /* Check for cached messages */
2809 if (progress_feedback) {
2810 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2811 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2813 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2815 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2818 /* Create the helper */
2819 helper = g_slice_new0 (GetMsgInfo);
2820 helper->header = g_object_ref (header);
2821 helper->mail_op = g_object_ref (self);
2822 helper->user_callback = user_callback;
2823 helper->user_data = user_data;
2824 helper->destroy_notify = NULL;
2825 helper->last_total_bytes = 0;
2826 helper->sum_total_bytes = 0;
2827 helper->total_bytes = tny_header_get_message_size (header);
2828 helper->more_msgs = NULL;
2829 helper->get_parts = NULL;
2832 modest_mail_operation_notify_start (self);
2834 /* notify about the start of the operation */
2835 ModestMailOperationState *state;
2836 state = modest_mail_operation_clone_state (self);
2839 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2841 g_slice_free (ModestMailOperationState, state);
2843 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2845 g_object_unref (G_OBJECT (folder));
2849 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2852 gboolean progress_feedback,
2853 GetMsgAsyncUserCallback user_callback,
2856 GetMsgInfo *helper = NULL;
2858 ModestMailOperationPrivate *priv;
2860 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2861 g_return_if_fail (TNY_IS_HEADER (header));
2863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2864 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2868 /* Check memory low */
2869 if (_check_memory_low (self)) {
2871 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2872 modest_mail_operation_notify_end (self);
2876 /* Get account and set it into mail_operation */
2877 folder = tny_header_get_folder (header);
2878 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2879 const gchar *acc_name;
2880 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2881 priv->account = modest_tny_account_store_get_server_account
2882 (modest_runtime_get_account_store (),
2884 TNY_ACCOUNT_TYPE_STORE);
2885 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2886 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2888 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2891 /* Check for cached messages */
2892 if (progress_feedback) {
2893 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2894 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2896 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2898 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2901 /* Create the helper */
2902 helper = g_slice_new0 (GetMsgInfo);
2903 helper->header = g_object_ref (header);
2904 helper->mail_op = g_object_ref (self);
2905 helper->user_callback = user_callback;
2906 helper->user_data = user_data;
2907 helper->destroy_notify = NULL;
2908 helper->last_total_bytes = 0;
2909 helper->sum_total_bytes = 0;
2910 helper->total_bytes = tny_header_get_message_size (header);
2911 helper->more_msgs = NULL;
2912 helper->get_parts = tny_list_create_iterator (parts);
2915 modest_mail_operation_notify_start (self);
2917 /* notify about the start of the operation */
2918 ModestMailOperationState *state;
2919 state = modest_mail_operation_clone_state (self);
2922 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2924 g_slice_free (ModestMailOperationState, state);
2926 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2928 g_object_unref (G_OBJECT (folder));
2932 get_msg_status_cb (GObject *obj,
2936 GetMsgInfo *helper = NULL;
2938 g_return_if_fail (status != NULL);
2940 /* Show only the status information we want */
2941 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2944 helper = (GetMsgInfo *) user_data;
2945 g_return_if_fail (helper != NULL);
2947 /* Notify progress */
2948 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2949 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2953 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2956 TnyFolder *folder = NULL;
2958 helper = (GetMsgInfo *) user_data;
2960 if (helper->header) {
2961 folder = tny_header_get_folder (helper->header);
2964 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2966 if (folder) g_object_unref (folder);
2970 get_msg_async_cb (TnyFolder *folder,
2976 GetMsgInfo *info = NULL;
2977 ModestMailOperationPrivate *priv = NULL;
2980 info = (GetMsgInfo *) user_data;
2982 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2985 if (info->more_msgs) {
2986 tny_iterator_next (info->more_msgs);
2987 finished = (tny_iterator_is_done (info->more_msgs));
2988 } else if (info->get_parts) {
2989 tny_iterator_next (info->get_parts);
2990 finished = (tny_iterator_is_done (info->get_parts));
2992 finished = (priv->done == priv->total) ? TRUE : FALSE;
2995 /* If canceled by the user, ignore the error given by Tinymail */
2999 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3001 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3002 priv->error = g_error_copy ((const GError *) err);
3004 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3006 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3007 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3008 "%s", err->message);
3010 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
3011 /* Set the success status before calling the user callback */
3012 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3015 if (info->header == NULL && msg)
3016 info->header = tny_msg_get_header (msg);
3018 /* Call the user callback */
3019 if (info->user_callback && (finished || (info->get_parts == NULL)))
3020 info->user_callback (info->mail_op, info->header, canceled,
3021 msg, err, info->user_data);
3023 /* Notify about operation end if this is the last callback */
3025 /* Free user data */
3026 if (info->destroy_notify)
3027 info->destroy_notify (info->user_data);
3029 /* Notify about operation end */
3030 modest_mail_operation_notify_end (info->mail_op);
3034 g_object_unref (info->msg);
3035 if (info->more_msgs)
3036 g_object_unref (info->more_msgs);
3038 g_object_unref (info->header);
3039 g_object_unref (info->mail_op);
3040 g_slice_free (GetMsgInfo, info);
3041 } else if (info->get_parts) {
3042 CamelStream *null_stream;
3043 TnyStream *tny_null_stream;
3046 if (info->msg == NULL && msg != NULL)
3047 info->msg = g_object_ref (msg);
3049 null_stream = camel_stream_null_new ();
3050 tny_null_stream = tny_camel_stream_new (null_stream);
3052 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
3053 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
3054 get_msg_async_get_part_cb,
3057 g_object_unref (tny_null_stream);
3058 g_object_unref (part);
3060 } else if (info->more_msgs) {
3061 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
3062 TnyFolder *folder = tny_header_get_folder (header);
3064 g_object_unref (info->header);
3065 info->header = g_object_ref (header);
3067 /* Retrieve the next message */
3068 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
3070 g_object_unref (header);
3071 g_object_unref (folder);
3073 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
3078 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
3079 TnyList *header_list,
3080 GetMsgAsyncUserCallback user_callback,
3082 GDestroyNotify notify)
3084 ModestMailOperationPrivate *priv = NULL;
3086 TnyIterator *iter = NULL;
3087 gboolean has_uncached_messages;
3089 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3091 /* Init mail operation */
3092 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3093 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3095 priv->total = tny_list_get_length(header_list);
3097 /* Check memory low */
3098 if (_check_memory_low (self)) {
3099 if (user_callback) {
3100 TnyHeader *header = NULL;
3103 if (tny_list_get_length (header_list) > 0) {
3104 iter = tny_list_create_iterator (header_list);
3105 header = (TnyHeader *) tny_iterator_get_current (iter);
3106 g_object_unref (iter);
3108 user_callback (self, header, FALSE, NULL, priv->error, user_data);
3110 g_object_unref (header);
3114 /* Notify about operation end */
3115 modest_mail_operation_notify_end (self);
3119 /* Check uncached messages */
3120 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
3121 !has_uncached_messages && !tny_iterator_is_done (iter);
3122 tny_iterator_next (iter)) {
3125 header = (TnyHeader *) tny_iterator_get_current (iter);
3126 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
3127 has_uncached_messages = TRUE;
3128 g_object_unref (header);
3130 g_object_unref (iter);
3131 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
3133 /* Get account and set it into mail_operation */
3134 if (tny_list_get_length (header_list) >= 1) {
3135 TnyIterator *iterator = tny_list_create_iterator (header_list);
3136 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
3138 TnyFolder *folder = tny_header_get_folder (header);
3140 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3141 g_object_unref (folder);
3143 g_object_unref (header);
3145 g_object_unref (iterator);
3148 msg_list_size = compute_message_list_size (header_list, 0);
3150 modest_mail_operation_notify_start (self);
3151 iter = tny_list_create_iterator (header_list);
3152 if (!tny_iterator_is_done (iter)) {
3153 /* notify about the start of the operation */
3154 ModestMailOperationState *state;
3155 state = modest_mail_operation_clone_state (self);
3158 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3161 GetMsgInfo *msg_info = NULL;
3162 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3163 TnyFolder *folder = tny_header_get_folder (header);
3165 /* Create the message info */
3166 msg_info = g_slice_new0 (GetMsgInfo);
3167 msg_info->mail_op = g_object_ref (self);
3168 msg_info->header = g_object_ref (header);
3169 msg_info->more_msgs = g_object_ref (iter);
3170 msg_info->user_callback = user_callback;
3171 msg_info->user_data = user_data;
3172 msg_info->destroy_notify = notify;
3173 msg_info->last_total_bytes = 0;
3174 msg_info->sum_total_bytes = 0;
3175 msg_info->total_bytes = msg_list_size;
3176 msg_info->msg = NULL;
3178 /* The callback will call it per each header */
3179 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3181 /* Free and go on */
3182 g_object_unref (header);
3183 g_object_unref (folder);
3184 g_slice_free (ModestMailOperationState, state);
3186 g_object_unref (iter);
3191 remove_msgs_async_cb (TnyFolder *folder,
3197 const gchar *account_name;
3198 TnyAccount *account;
3199 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3200 ModestMailOperation *self;
3201 ModestMailOperationPrivate *priv;
3202 ModestProtocolRegistry *protocol_registry;
3203 SyncFolderHelper *helper;
3205 self = (ModestMailOperation *) user_data;
3206 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3207 protocol_registry = modest_runtime_get_protocol_registry ();
3209 if (canceled || err) {
3210 /* If canceled by the user, ignore the error given by Tinymail */
3212 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3214 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3215 priv->error = g_error_copy ((const GError *) err);
3216 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3219 modest_mail_operation_notify_end (self);
3220 g_object_unref (self);
3224 account = modest_tny_folder_get_account (folder);
3225 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3226 account_proto = modest_tny_account_get_protocol_type (account);
3227 g_object_unref (account);
3229 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3230 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3240 helper = g_slice_new0 (SyncFolderHelper);
3241 helper->mail_op = g_object_ref (self);
3242 helper->user_callback = NULL;
3243 helper->user_data = NULL;
3246 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3248 /* Remove the extra reference */
3249 g_object_unref (self);
3253 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3255 gboolean remove_to_trash /*ignored*/)
3257 TnyFolder *folder = NULL;
3258 ModestMailOperationPrivate *priv;
3259 TnyIterator *iter = NULL;
3260 TnyHeader *header = NULL;
3261 TnyList *remove_headers = NULL;
3262 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3263 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3265 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3266 g_return_if_fail (TNY_IS_LIST (headers));
3268 if (remove_to_trash)
3269 g_warning ("remove to trash is not implemented");
3271 if (tny_list_get_length(headers) == 0) {
3272 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3273 goto cleanup; /* nothing to do */
3276 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3278 /* Get folder from first header and sync it */
3279 iter = tny_list_create_iterator (headers);
3280 header = TNY_HEADER (tny_iterator_get_current (iter));
3281 g_object_unref (iter);
3283 folder = tny_header_get_folder (header);
3284 if (!TNY_IS_FOLDER(folder)) {
3285 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3289 /* Use the merged folder if we're removing messages from outbox */
3290 if (modest_tny_folder_is_local_folder (folder)) {
3291 ModestTnyLocalFoldersAccount *local_account;
3293 local_account = (ModestTnyLocalFoldersAccount *)
3294 modest_tny_account_store_get_local_folders_account (accstore);
3295 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3296 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3297 g_object_unref (folder);
3298 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3300 g_object_unref (local_account);
3303 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3304 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3306 while (!tny_iterator_is_done (headers_iter)) {
3307 TnyTransportAccount *traccount = NULL;
3308 TnyHeader *hdr = NULL;
3310 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3311 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3314 ModestTnySendQueueStatus status;
3315 ModestTnySendQueue *send_queue;
3317 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3318 if (TNY_IS_SEND_QUEUE (send_queue)) {
3321 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3322 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3323 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3324 if (G_UNLIKELY (remove_headers == NULL))
3325 remove_headers = tny_simple_list_new ();
3326 tny_list_append(remove_headers, G_OBJECT(hdr));
3330 g_object_unref(traccount);
3332 g_object_unref(hdr);
3333 tny_iterator_next (headers_iter);
3335 g_object_unref(headers_iter);
3338 /* Get account and set it into mail_operation */
3339 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3340 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3341 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3343 if (!remove_headers)
3344 remove_headers = g_object_ref (headers);
3346 /* remove message from folder */
3347 modest_mail_operation_notify_start (self);
3348 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3349 NULL, g_object_ref (self));
3353 g_object_unref (remove_headers);
3355 g_object_unref (header);
3357 g_object_unref (folder);
3361 notify_progress_of_multiple_messages (ModestMailOperation *self,
3363 gint *last_total_bytes,
3364 gint *sum_total_bytes,
3366 gboolean increment_done)
3368 ModestMailOperationPrivate *priv;
3369 ModestMailOperationState *state;
3370 gboolean is_num_bytes = FALSE;
3372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3374 /* We know that tinymail sends us information about
3375 * transferred bytes with this particular message
3377 if (status->message)
3378 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3380 state = modest_mail_operation_clone_state (self);
3381 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3382 /* We know that we're in a different message when the
3383 total number of bytes to transfer is different. Of
3384 course it could fail if we're transferring messages
3385 of the same size, but this is a workarround */
3386 if (status->of_total != *last_total_bytes) {
3387 /* We need to increment the done when there is
3388 no information about each individual
3389 message, we need to do this in message
3390 transfers, and we don't do it for getting
3394 *sum_total_bytes += *last_total_bytes;
3395 *last_total_bytes = status->of_total;
3397 state->bytes_done += status->position + *sum_total_bytes;
3398 state->bytes_total = total_bytes;
3400 /* Notify the status change. Only notify about changes
3401 referred to bytes */
3402 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3406 g_slice_free (ModestMailOperationState, state);
3410 transfer_msgs_status_cb (GObject *obj,
3414 XFerMsgsAsyncHelper *helper;
3416 g_return_if_fail (status != NULL);
3418 /* Show only the status information we want */
3419 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3422 helper = (XFerMsgsAsyncHelper *) user_data;
3423 g_return_if_fail (helper != NULL);
3425 /* Notify progress */
3426 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3427 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3431 transfer_msgs_sync_folder_cb (TnyFolder *self,
3436 XFerMsgsAsyncHelper *helper;
3437 /* We don't care here about the results of the
3439 helper = (XFerMsgsAsyncHelper *) user_data;
3441 /* Notify about operation end */
3442 modest_mail_operation_notify_end (helper->mail_op);
3444 /* If user defined callback function was defined, call it */
3445 if (helper->user_callback)
3446 helper->user_callback (helper->mail_op, helper->user_data);
3449 if (helper->more_msgs)
3450 g_object_unref (helper->more_msgs);
3451 if (helper->headers)
3452 g_object_unref (helper->headers);
3453 if (helper->dest_folder)
3454 g_object_unref (helper->dest_folder);
3455 if (helper->mail_op)
3456 g_object_unref (helper->mail_op);
3457 g_slice_free (XFerMsgsAsyncHelper, helper);
3461 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3463 XFerMsgsAsyncHelper *helper;
3464 ModestMailOperation *self;
3465 ModestMailOperationPrivate *priv;
3466 gboolean finished = TRUE;
3468 helper = (XFerMsgsAsyncHelper *) user_data;
3469 self = helper->mail_op;
3471 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3474 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3476 priv->error = g_error_copy (err);
3478 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3479 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3480 if (helper->more_msgs) {
3481 /* We'll transfer the next message in the list */
3482 tny_iterator_next (helper->more_msgs);
3483 if (!tny_iterator_is_done (helper->more_msgs)) {
3484 GObject *next_header;
3485 g_object_unref (helper->headers);
3486 helper->headers = tny_simple_list_new ();
3487 next_header = tny_iterator_get_current (helper->more_msgs);
3488 tny_list_append (helper->headers, next_header);
3489 g_object_unref (next_header);
3495 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3500 /* Synchronize the source folder contents. This should
3501 be done by tinymail but the camel_folder_sync it's
3502 actually disabled in transfer_msgs_thread_clean
3503 because it's supposed to cause hangs */
3504 tny_folder_sync_async (folder, helper->delete,
3505 transfer_msgs_sync_folder_cb,
3508 /* Transfer more messages */
3509 tny_folder_transfer_msgs_async (folder,
3511 helper->dest_folder,
3514 transfer_msgs_status_cb,
3519 /* Computes the size of the messages the headers in the list belongs
3520 to. If num_elements is different from 0 then it only takes into
3521 account the first num_elements for the calculation */
3523 compute_message_list_size (TnyList *headers,
3527 guint size = 0, element = 0;
3529 /* If num_elements is not valid then take all into account */
3530 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3531 num_elements = tny_list_get_length (headers);
3533 iter = tny_list_create_iterator (headers);
3534 while (!tny_iterator_is_done (iter) && element < num_elements) {
3535 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3536 size += tny_header_get_message_size (header);
3537 g_object_unref (header);
3538 tny_iterator_next (iter);
3541 g_object_unref (iter);
3547 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3550 gboolean delete_original,
3551 XferMsgsAsyncUserCallback user_callback,
3554 ModestMailOperationPrivate *priv = NULL;
3555 TnyIterator *iter = NULL;
3556 TnyFolder *src_folder = NULL;
3557 XFerMsgsAsyncHelper *helper = NULL;
3558 TnyHeader *header = NULL;
3559 ModestTnyFolderRules rules = 0;
3560 TnyAccount *dst_account = NULL;
3561 gboolean leave_on_server;
3562 ModestMailOperationState *state;
3563 ModestProtocolRegistry *protocol_registry;
3564 ModestProtocolType account_protocol;
3566 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3567 g_return_if_fail (headers && TNY_IS_LIST (headers));
3568 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3570 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3571 protocol_registry = modest_runtime_get_protocol_registry ();
3573 priv->total = tny_list_get_length (headers);
3575 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3576 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3578 /* Apply folder rules */
3579 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3580 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3581 /* Set status failed and set an error */
3582 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3583 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3584 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3585 _CS_UNABLE_TO_PASTE_HERE);
3586 /* Notify the queue */
3587 modest_mail_operation_notify_end (self);
3591 /* Get source folder */
3592 iter = tny_list_create_iterator (headers);
3593 header = TNY_HEADER (tny_iterator_get_current (iter));
3595 src_folder = tny_header_get_folder (header);
3596 g_object_unref (header);
3598 g_object_unref (iter);
3600 if (src_folder == NULL) {
3601 /* Notify the queue */
3602 modest_mail_operation_notify_end (self);
3604 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3609 /* Check folder source and destination */
3610 if (src_folder == folder) {
3611 /* Set status failed and set an error */
3612 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3613 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3614 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3615 _("mail_in_ui_folder_copy_target_error"));
3617 /* Notify the queue */
3618 modest_mail_operation_notify_end (self);
3621 g_object_unref (src_folder);
3625 /* Create the helper */
3626 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3627 helper->mail_op = g_object_ref(self);
3628 helper->dest_folder = g_object_ref(folder);
3629 helper->user_callback = user_callback;
3630 helper->user_data = user_data;
3631 helper->last_total_bytes = 0;
3632 helper->sum_total_bytes = 0;
3633 helper->total_bytes = compute_message_list_size (headers, 0);
3635 /* Get account and set it into mail_operation */
3636 priv->account = modest_tny_folder_get_account (src_folder);
3637 dst_account = modest_tny_folder_get_account (folder);
3639 if (priv->account == dst_account) {
3640 /* Transfer all messages at once using the fast
3641 * method. Note that depending on the server this
3642 * might not be that fast, and might not be
3643 * user-cancellable either */
3644 helper->headers = g_object_ref (headers);
3645 helper->more_msgs = NULL;
3647 /* Transfer messages one by one so the user can cancel
3650 helper->headers = tny_simple_list_new ();
3651 helper->more_msgs = tny_list_create_iterator (headers);
3652 hdr = tny_iterator_get_current (helper->more_msgs);
3653 tny_list_append (helper->headers, hdr);
3654 g_object_unref (hdr);
3657 /* If leave_on_server is set to TRUE then don't use
3658 delete_original, we always pass FALSE. This is because
3659 otherwise tinymail will try to sync the source folder and
3660 this could cause an error if we're offline while
3661 transferring an already downloaded message from a POP
3663 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3664 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3665 const gchar *account_name;
3667 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3668 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3671 leave_on_server = FALSE;
3674 /* Do not delete messages if leave on server is TRUE */
3675 helper->delete = (leave_on_server) ? FALSE : delete_original;
3677 modest_mail_operation_notify_start (self);
3679 /* Start notifying progress */
3680 state = modest_mail_operation_clone_state (self);
3683 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3684 g_slice_free (ModestMailOperationState, state);
3686 tny_folder_transfer_msgs_async (src_folder,
3691 transfer_msgs_status_cb,
3693 g_object_unref (src_folder);
3694 g_object_unref (dst_account);
3699 on_refresh_folder (TnyFolder *folder,
3704 RefreshAsyncHelper *helper = NULL;
3705 ModestMailOperation *self = NULL;
3706 ModestMailOperationPrivate *priv = NULL;
3708 helper = (RefreshAsyncHelper *) user_data;
3709 self = helper->mail_op;
3710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3712 g_return_if_fail(priv!=NULL);
3715 priv->error = g_error_copy (error);
3716 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3721 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3722 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3723 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3724 _("Error trying to refresh the contents of %s"),
3725 tny_folder_get_name (folder));
3729 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3732 /* Call user defined callback, if it exists */
3733 if (helper->user_callback) {
3735 /* This is not a GDK lock because we are a Tinymail callback and
3736 * Tinymail already acquires the Gdk lock */
3737 helper->user_callback (self, folder, helper->user_data);
3741 g_slice_free (RefreshAsyncHelper, helper);
3743 /* Notify about operation end */
3744 modest_mail_operation_notify_end (self);
3745 g_object_unref(self);
3749 on_refresh_folder_status_update (GObject *obj,
3753 RefreshAsyncHelper *helper = NULL;
3754 ModestMailOperation *self = NULL;
3755 ModestMailOperationPrivate *priv = NULL;
3756 ModestMailOperationState *state;
3758 g_return_if_fail (user_data != NULL);
3759 g_return_if_fail (status != NULL);
3761 /* Show only the status information we want */
3762 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3765 helper = (RefreshAsyncHelper *) user_data;
3766 self = helper->mail_op;
3767 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3769 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3771 priv->done = status->position;
3772 priv->total = status->of_total;
3774 state = modest_mail_operation_clone_state (self);
3776 /* This is not a GDK lock because we are a Tinymail callback and
3777 * Tinymail already acquires the Gdk lock */
3778 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3780 g_slice_free (ModestMailOperationState, state);
3784 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3786 RefreshAsyncUserCallback user_callback,
3789 ModestMailOperationPrivate *priv = NULL;
3790 RefreshAsyncHelper *helper = NULL;
3792 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3794 /* Check memory low */
3795 if (_check_memory_low (self)) {
3797 user_callback (self, folder, user_data);
3798 /* Notify about operation end */
3799 modest_mail_operation_notify_end (self);
3803 /* Get account and set it into mail_operation */
3804 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3805 priv->account = modest_tny_folder_get_account (folder);
3806 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3808 /* Create the helper */
3809 helper = g_slice_new0 (RefreshAsyncHelper);
3810 helper->mail_op = g_object_ref(self);
3811 helper->user_callback = user_callback;
3812 helper->user_data = user_data;
3814 modest_mail_operation_notify_start (self);
3816 /* notify that the operation was started */
3817 ModestMailOperationState *state;
3818 state = modest_mail_operation_clone_state (self);
3821 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3823 g_slice_free (ModestMailOperationState, state);
3825 tny_folder_refresh_async (folder,
3827 on_refresh_folder_status_update,
3832 run_queue_notify_and_destroy (RunQueueHelper *helper,
3833 ModestMailOperationStatus status)
3835 ModestMailOperationPrivate *priv;
3838 if (helper->error_handler &&
3839 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3840 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3841 if (helper->start_handler &&
3842 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3843 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3844 if (helper->stop_handler &&
3845 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3846 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3849 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3850 priv->status = status;
3853 modest_mail_operation_notify_end (helper->self);
3856 g_object_unref (helper->queue);
3857 g_object_unref (helper->self);
3858 g_slice_free (RunQueueHelper, helper);
3862 run_queue_stop (ModestTnySendQueue *queue,
3865 RunQueueHelper *helper;
3867 g_debug ("%s sending queue stopped", __FUNCTION__);
3869 helper = (RunQueueHelper *) user_data;
3870 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3874 modest_mail_operation_run_queue (ModestMailOperation *self,
3875 ModestTnySendQueue *queue)
3877 ModestMailOperationPrivate *priv;
3878 RunQueueHelper *helper;
3880 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3881 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3882 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3884 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3885 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3886 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3888 /* Create the helper */
3889 helper = g_slice_new0 (RunQueueHelper);
3890 helper->queue = g_object_ref (queue);
3891 helper->self = g_object_ref (self);
3892 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3893 G_CALLBACK (run_queue_stop),
3896 /* Notify operation has started */
3897 modest_mail_operation_notify_start (self);
3898 g_debug ("%s, run queue started", __FUNCTION__);
3902 queue_wakeup_callback (ModestTnySendQueue *queue,
3907 ModestMailOperation *mail_op;
3908 ModestMailOperationPrivate *priv;
3910 mail_op = (ModestMailOperation *) userdata;
3911 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3913 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3914 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3917 modest_mail_operation_notify_end (mail_op);
3918 g_object_unref (mail_op);
3922 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3923 ModestTnySendQueue *queue)
3925 ModestMailOperationPrivate *priv;
3927 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3928 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3929 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3931 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3932 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3933 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3935 g_object_ref (self);
3937 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3938 modest_mail_operation_notify_start (self);
3942 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3944 ModestMailOperation *self = (ModestMailOperation *) userdata;
3945 ModestMailOperationPrivate *priv;
3947 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3948 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3949 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3951 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3953 modest_mail_operation_notify_end (self);
3954 g_object_unref (self);
3958 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3960 ModestMailOperationPrivate *priv;
3962 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3963 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3964 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3966 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3968 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3969 priv->account = NULL;
3970 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3972 modest_mail_operation_notify_start (self);
3973 g_object_ref (self);
3974 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3978 sync_folder_finish_callback (TnyFolder *self,
3984 ModestMailOperationPrivate *priv;
3985 SyncFolderHelper *helper;
3987 helper = (SyncFolderHelper *) user_data;
3988 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
3990 /* If canceled by the user, ignore the error given by Tinymail */
3992 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3994 /* If the operation was a sync then the status is
3995 failed, but if it's part of another operation then
3996 just set it as finished with errors */
3997 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
3998 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4000 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
4001 priv->error = g_error_copy ((const GError *) err);
4002 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
4004 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4008 if (helper->user_callback)
4009 helper->user_callback (helper->mail_op, self, helper->user_data);
4011 modest_mail_operation_notify_end (helper->mail_op);
4014 g_object_unref (helper->mail_op);
4015 g_slice_free (SyncFolderHelper, helper);
4019 modest_mail_operation_sync_folder (ModestMailOperation *self,
4022 SyncFolderCallback callback,
4025 ModestMailOperationPrivate *priv;
4026 SyncFolderHelper *helper;
4028 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
4029 g_return_if_fail (TNY_IS_FOLDER (folder));
4030 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
4032 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
4033 priv->account = modest_tny_folder_get_account (folder);
4034 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
4037 helper = g_slice_new0 (SyncFolderHelper);
4038 helper->mail_op = g_object_ref (self);
4039 helper->user_callback = callback;
4040 helper->user_data = user_data;
4042 modest_mail_operation_notify_start (self);
4043 tny_folder_sync_async (folder, expunge,
4044 (TnyFolderCallback) sync_folder_finish_callback,
4049 modest_mail_operation_notify_start (ModestMailOperation *self)
4051 ModestMailOperationPrivate *priv = NULL;
4053 g_return_if_fail (self);
4055 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4057 /* Ensure that all the fields are filled correctly */
4058 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
4060 /* Notify the observers about the mail operation. We do not
4061 wrapp this emission because we assume that this function is
4062 always called from within the main lock */
4063 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
4068 * It's used by the mail operation queue to notify the observers
4069 * attached to that signal that the operation finished. We need to use
4070 * that because tinymail does not give us the progress of a given
4071 * operation when it finishes (it directly calls the operation
4075 modest_mail_operation_notify_end (ModestMailOperation *self)
4077 ModestMailOperationPrivate *priv = NULL;
4079 g_return_if_fail (self);
4081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4083 /* Notify the observers about the mail operation end. We do
4084 not wrapp this emission because we assume that this
4085 function is always called from within the main lock */
4086 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
4088 /* Remove the error user data */
4089 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
4090 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
4094 modest_mail_operation_get_account (ModestMailOperation *self)
4096 ModestMailOperationPrivate *priv = NULL;
4098 g_return_val_if_fail (self, NULL);
4100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4102 return (priv->account) ? g_object_ref (priv->account) : NULL;
4106 modest_mail_operation_noop (ModestMailOperation *self)
4108 ModestMailOperationPrivate *priv = NULL;
4110 g_return_if_fail (self);
4112 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4113 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4114 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
4118 /* This mail operation does nothing actually */
4119 modest_mail_operation_notify_start (self);
4120 modest_mail_operation_notify_end (self);
4125 modest_mail_operation_to_string (ModestMailOperation *self)
4127 const gchar *type, *status, *account_id;
4128 ModestMailOperationPrivate *priv = NULL;
4130 g_return_val_if_fail (self, NULL);
4132 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4134 /* new operations don't have anything interesting */
4135 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
4136 return g_strdup_printf ("%p <new operation>", self);
4138 switch (priv->op_type) {
4139 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
4140 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
4141 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
4142 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
4143 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
4144 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
4145 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
4146 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
4147 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
4148 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
4149 default: type = "UNEXPECTED"; break;
4152 switch (priv->status) {
4153 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4154 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4155 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4156 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4157 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4158 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4159 default: status= "UNEXPECTED"; break;
4162 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4164 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4165 priv->done, priv->total,
4166 priv->error && priv->error->message ? priv->error->message : "");
4170 * Once the mail operations were objects this will be no longer
4171 * needed. I don't like it, but we need it for the moment
4174 _check_memory_low (ModestMailOperation *mail_op)
4176 if (modest_platform_check_memory_low (NULL, FALSE)) {
4177 ModestMailOperationPrivate *priv;
4179 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4180 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4181 g_set_error (&(priv->error),
4182 MODEST_MAIL_OPERATION_ERROR,
4183 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4184 "Not enough memory to complete the operation");