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)));
1776 modest_account_mgr_set_has_new_mails (modest_runtime_get_account_mgr (),
1777 info->account_name, TRUE);
1779 while (!tny_iterator_is_done (new_headers_iter)) {
1780 TnyHeader *header = NULL;
1782 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1783 /* Apply per-message size limits */
1784 if (tny_header_get_message_size (header) < max_size)
1785 g_ptr_array_add (new_headers_array, g_object_ref (header));
1787 g_object_unref (header);
1788 tny_iterator_next (new_headers_iter);
1790 g_object_unref (new_headers_iter);
1792 tny_folder_remove_observer (inbox, info->inbox_observer);
1793 g_object_unref (info->inbox_observer);
1794 info->inbox_observer = NULL;
1797 if (new_headers_array->len == 0) {
1798 g_ptr_array_free (new_headers_array, FALSE);
1802 /* Get per-account message amount retrieval limit */
1803 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1804 if (retrieve_limit == 0)
1805 retrieve_limit = G_MAXINT;
1807 /* Get per-account retrieval type */
1808 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1809 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1812 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1814 /* Copy the headers to a list and free the array */
1815 new_headers = tny_simple_list_new ();
1816 for (i=0; i < new_headers_array->len; i++) {
1817 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1818 /* We want the first element to be the most recent
1819 one, that's why we reverse the list */
1820 tny_list_prepend (new_headers, G_OBJECT (header));
1822 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1823 g_ptr_array_free (new_headers_array, FALSE);
1825 if (!headers_only && (tny_list_get_length (new_headers) > 0)) {
1828 GetMsgInfo *msg_info;
1831 priv->total = MIN (tny_list_get_length (new_headers), retrieve_limit);
1833 iter = tny_list_create_iterator (new_headers);
1835 /* Create the message info */
1836 msg_info = g_slice_new0 (GetMsgInfo);
1837 msg_info->mail_op = g_object_ref (info->mail_op);
1838 msg_info->total_bytes = compute_message_list_size (new_headers, priv->total);
1839 msg_info->more_msgs = g_object_ref (iter);
1840 msg_info->msg = NULL;
1841 msg_info->user_data = info;
1843 while ((msg_num < priv->total ) && !tny_iterator_is_done (iter)) {
1844 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1845 TnyFolder *folder = tny_header_get_folder (header);
1847 /* Get message in an async way */
1848 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1851 g_object_unref (folder);
1852 g_object_unref (header);
1855 tny_iterator_next (iter);
1857 g_object_unref (iter);
1858 g_object_unref (new_headers);
1860 /* The mail operation will finish when the last
1861 message is retrieved */
1865 /* If we don't have to retrieve the new messages then
1867 update_account_send_mail (info);
1869 /* Check if the operation was a success */
1871 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1873 /* Call the user callback and free */
1874 update_account_notify_user_and_free (info, new_headers);
1878 inbox_refresh_status_update (GObject *obj,
1882 UpdateAccountInfo *info = NULL;
1883 ModestMailOperation *self = NULL;
1884 ModestMailOperationPrivate *priv = NULL;
1885 ModestMailOperationState *state;
1887 g_return_if_fail (user_data != NULL);
1888 g_return_if_fail (status != NULL);
1890 /* Show only the status information we want */
1891 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
1894 info = (UpdateAccountInfo *) user_data;
1895 self = info->mail_op;
1896 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1898 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1900 priv->done = status->position;
1901 priv->total = status->of_total;
1903 state = modest_mail_operation_clone_state (self);
1905 /* This is not a GDK lock because we are a Tinymail callback and
1906 * Tinymail already acquires the Gdk lock */
1907 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1909 g_slice_free (ModestMailOperationState, state);
1913 recurse_folders_async_cb (TnyFolderStore *folder_store,
1919 UpdateAccountInfo *info;
1920 ModestMailOperationPrivate *priv;
1922 info = (UpdateAccountInfo *) user_data;
1923 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1925 if (err || canceled) {
1926 /* If the error was previosly set by another callback
1927 don't set it again */
1929 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1931 priv->error = g_error_copy (err);
1933 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1934 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1938 /* We're not getting INBOX children if we don't want to poke all */
1939 TnyIterator *iter = tny_list_create_iterator (list);
1940 while (!tny_iterator_is_done (iter)) {
1941 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1943 /* Add to the list of all folders */
1944 tny_list_append (info->folders, (GObject *) folder);
1946 if (info->poke_all) {
1947 TnyList *folders = tny_simple_list_new ();
1948 /* Add pending call */
1949 info->pending_calls++;
1951 tny_folder_store_get_folders_async (folder, folders, NULL, FALSE,
1952 recurse_folders_async_cb,
1954 g_object_unref (folders);
1957 g_object_unref (G_OBJECT (folder));
1959 tny_iterator_next (iter);
1961 g_object_unref (G_OBJECT (iter));
1964 /* Remove my own pending call */
1965 info->pending_calls--;
1967 /* This means that we have all the folders */
1968 if (info->pending_calls == 0) {
1969 TnyIterator *iter_all_folders;
1970 TnyFolder *inbox = NULL;
1972 /* If there was any error do not continue */
1974 update_account_notify_user_and_free (info, NULL);
1978 iter_all_folders = tny_list_create_iterator (info->folders);
1980 /* Do a poke status over all folders */
1981 while (!tny_iterator_is_done (iter_all_folders) &&
1982 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1983 TnyFolder *folder = NULL;
1985 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1987 if (!info->update_folder_counts && tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1988 /* Get a reference to the INBOX */
1989 inbox = g_object_ref (folder);
1991 /* Issue a poke status over the folder */
1993 tny_folder_poke_status (folder);
1996 /* Free and go to next */
1997 g_object_unref (folder);
1998 tny_iterator_next (iter_all_folders);
2000 g_object_unref (iter_all_folders);
2002 /* Refresh the INBOX */
2004 /* Refresh the folder. Our observer receives
2005 * the new emails during folder refreshes, so
2006 * we can use observer->new_headers
2008 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
2009 tny_folder_add_observer (inbox, info->inbox_observer);
2011 /* Refresh the INBOX */
2012 tny_folder_refresh_async (inbox, inbox_refreshed_cb, inbox_refresh_status_update, info);
2013 g_object_unref (inbox);
2015 /* We could not perform the inbox refresh but
2016 we'll try to send mails anyway */
2017 inbox_refreshed_cb (inbox, FALSE, NULL, info);
2023 modest_mail_operation_update_account (ModestMailOperation *self,
2024 const gchar *account_name,
2026 gboolean interactive,
2027 UpdateAccountCallback callback,
2030 UpdateAccountInfo *info = NULL;
2031 ModestMailOperationPrivate *priv = NULL;
2032 ModestTnyAccountStore *account_store = NULL;
2034 ModestMailOperationState *state;
2036 /* Init mail operation */
2037 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2040 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2041 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
2043 /* Get the store account */
2044 account_store = modest_runtime_get_account_store ();
2046 modest_tny_account_store_get_server_account (account_store,
2048 TNY_ACCOUNT_TYPE_STORE);
2050 /* The above function could return NULL */
2051 if (!priv->account) {
2052 /* Check if the operation was a success */
2053 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2054 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2056 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2058 /* Call the user callback */
2060 callback (self, NULL, user_data);
2062 /* Notify about operation end */
2063 modest_mail_operation_notify_end (self);
2068 /* We have once seen priv->account getting finalized during this code,
2069 * therefore adding a reference (bug #82296) */
2071 g_object_ref (priv->account);
2073 /* Create the helper object */
2074 info = g_slice_new0 (UpdateAccountInfo);
2075 info->pending_calls = 1;
2076 info->folders = tny_simple_list_new ();
2077 info->mail_op = g_object_ref (self);
2078 info->poke_all = poke_all;
2079 info->interactive = interactive;
2080 info->update_folder_counts = FALSE;
2081 info->account_name = g_strdup (account_name);
2082 info->callback = callback;
2083 info->user_data = user_data;
2085 /* Set account busy */
2086 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2087 modest_mail_operation_notify_start (self);
2089 /* notify about the start of the operation */
2090 state = modest_mail_operation_clone_state (self);
2094 /* Start notifying progress */
2095 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2096 g_slice_free (ModestMailOperationState, state);
2098 /* Get all folders and continue in the callback */
2099 folders = tny_simple_list_new ();
2100 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2101 folders, NULL, TRUE,
2102 recurse_folders_async_cb,
2104 g_object_unref (folders);
2106 g_object_unref (priv->account);
2111 modest_mail_operation_update_folder_counts (ModestMailOperation *self,
2112 const gchar *account_name)
2114 UpdateAccountInfo *info = NULL;
2115 ModestMailOperationPrivate *priv = NULL;
2116 ModestTnyAccountStore *account_store = NULL;
2118 ModestMailOperationState *state;
2120 /* Init mail operation */
2121 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2124 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2125 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UPDATE_FOLDER_COUNTS;
2127 /* Get the store account */
2128 account_store = modest_runtime_get_account_store ();
2130 modest_tny_account_store_get_server_account (account_store,
2132 TNY_ACCOUNT_TYPE_STORE);
2134 /* The above function could return NULL */
2135 if (!priv->account) {
2136 /* Check if the operation was a success */
2137 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2138 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2140 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2142 /* Notify about operation end */
2143 modest_mail_operation_notify_end (self);
2148 /* We have once seen priv->account getting finalized during this code,
2149 * therefore adding a reference (bug #82296) */
2151 g_object_ref (priv->account);
2153 /* Create the helper object */
2154 info = g_slice_new0 (UpdateAccountInfo);
2155 info->pending_calls = 1;
2156 info->folders = tny_simple_list_new ();
2157 info->mail_op = g_object_ref (self);
2158 info->poke_all = TRUE;
2159 info->interactive = FALSE;
2160 info->update_folder_counts = TRUE;
2161 info->account_name = g_strdup (account_name);
2162 info->callback = NULL;
2163 info->user_data = NULL;
2165 /* Set account busy */
2166 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
2167 modest_mail_operation_notify_start (self);
2169 /* notify about the start of the operation */
2170 state = modest_mail_operation_clone_state (self);
2174 /* Start notifying progress */
2175 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2176 g_slice_free (ModestMailOperationState, state);
2178 /* Get all folders and continue in the callback */
2179 folders = tny_simple_list_new ();
2180 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
2181 folders, NULL, TRUE,
2182 recurse_folders_async_cb,
2184 g_object_unref (folders);
2186 g_object_unref (priv->account);
2191 * Used to notify the queue from the main
2192 * loop. We call it inside an idle call to achieve that
2195 idle_notify_queue (gpointer data)
2197 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
2199 gdk_threads_enter ();
2200 modest_mail_operation_notify_end (mail_op);
2201 gdk_threads_leave ();
2202 g_object_unref (mail_op);
2208 compare_headers_by_date (gconstpointer a,
2211 TnyHeader **header1, **header2;
2212 time_t sent1, sent2;
2214 header1 = (TnyHeader **) a;
2215 header2 = (TnyHeader **) b;
2217 sent1 = tny_header_get_date_sent (*header1);
2218 sent2 = tny_header_get_date_sent (*header2);
2220 /* We want the most recent ones (greater time_t) at the
2229 /* ******************************************************************* */
2230 /* ************************** STORE ACTIONS ************************* */
2231 /* ******************************************************************* */
2234 ModestMailOperation *mail_op;
2235 CreateFolderUserCallback callback;
2241 create_folder_cb (TnyFolderStore *parent_folder,
2243 TnyFolder *new_folder,
2247 ModestMailOperationPrivate *priv;
2248 CreateFolderInfo *info;
2250 info = (CreateFolderInfo *) user_data;
2251 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2253 if (canceled || err) {
2254 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2256 priv->error = g_error_copy (err);
2258 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2259 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2262 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2265 /* The user will unref the new_folder */
2267 info->callback (info->mail_op, parent_folder,
2268 new_folder, info->user_data);
2270 /* Notify about operation end */
2271 modest_mail_operation_notify_end (info->mail_op);
2274 g_object_unref (info->mail_op);
2275 g_slice_free (CreateFolderInfo, info);
2279 modest_mail_operation_create_folder (ModestMailOperation *self,
2280 TnyFolderStore *parent,
2282 CreateFolderUserCallback callback,
2285 ModestMailOperationPrivate *priv;
2287 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2288 g_return_if_fail (name);
2290 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2291 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2292 priv->account = (TNY_IS_ACCOUNT (parent)) ?
2293 g_object_ref (parent) :
2294 modest_tny_folder_get_account (TNY_FOLDER (parent));
2296 /* Check for already existing folder */
2297 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
2298 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2299 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2300 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2301 _CS("ckdg_ib_folder_already_exists"));
2305 if (TNY_IS_FOLDER (parent)) {
2306 /* Check folder rules */
2307 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2308 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2309 /* Set status failed and set an error */
2310 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2311 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2312 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2313 _("mail_in_ui_folder_create_error"));
2317 if (!priv->error && (!strcmp (name, " ") || strchr (name, '/'))) {
2318 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2319 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2320 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2321 _("mail_in_ui_folder_create_error"));
2325 CreateFolderInfo *info;
2327 info = g_slice_new0 (CreateFolderInfo);
2328 info->mail_op = g_object_ref (self);
2329 info->callback = callback;
2330 info->user_data = user_data;
2332 modest_mail_operation_notify_start (self);
2334 /* Create the folder */
2335 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
2338 /* Call the user callback anyway */
2340 callback (self, parent, NULL, user_data);
2341 /* Notify about operation end */
2342 modest_mail_operation_notify_end (self);
2347 modest_mail_operation_remove_folder (ModestMailOperation *self,
2349 gboolean remove_to_trash)
2351 ModestMailOperationPrivate *priv;
2352 ModestTnyFolderRules rules;
2354 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2355 g_return_if_fail (TNY_IS_FOLDER (folder));
2357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2359 /* Check folder rules */
2360 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2361 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
2362 /* Set status failed and set an error */
2363 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2364 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2365 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2366 _("mail_in_ui_folder_delete_error"));
2370 /* Get the account */
2371 priv->account = modest_tny_folder_get_account (folder);
2372 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2374 /* Delete folder or move to trash */
2375 if (remove_to_trash) {
2376 TnyFolder *trash_folder = NULL;
2377 trash_folder = modest_tny_account_get_special_folder (priv->account,
2378 TNY_FOLDER_TYPE_TRASH);
2379 /* TODO: error_handling */
2381 modest_mail_operation_notify_start (self);
2382 modest_mail_operation_xfer_folder (self, folder,
2383 TNY_FOLDER_STORE (trash_folder),
2385 g_object_unref (trash_folder);
2387 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
2390 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
2392 modest_mail_operation_notify_start (self);
2393 tny_folder_store_remove_folder (parent, folder, &(priv->error));
2394 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
2397 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2399 g_object_unref (parent);
2401 g_warning ("%s: could not get parent folder", __FUNCTION__);
2405 /* Notify about operation end */
2406 modest_mail_operation_notify_end (self);
2410 transfer_folder_status_cb (GObject *obj,
2414 ModestMailOperation *self;
2415 ModestMailOperationPrivate *priv;
2416 ModestMailOperationState *state;
2417 XFerFolderAsyncHelper *helper;
2419 g_return_if_fail (status != NULL);
2421 /* Show only the status information we want */
2422 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
2425 helper = (XFerFolderAsyncHelper *) user_data;
2426 g_return_if_fail (helper != NULL);
2428 self = helper->mail_op;
2429 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2431 priv->done = status->position;
2432 priv->total = status->of_total;
2434 state = modest_mail_operation_clone_state (self);
2436 /* This is not a GDK lock because we are a Tinymail callback
2437 * which is already GDK locked by Tinymail */
2439 /* no gdk_threads_enter (), CHECKED */
2441 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2443 /* no gdk_threads_leave (), CHECKED */
2445 g_slice_free (ModestMailOperationState, state);
2449 transfer_folder_cb (TnyFolder *folder,
2451 TnyFolderStore *into,
2452 TnyFolder *new_folder,
2456 XFerFolderAsyncHelper *helper;
2457 ModestMailOperation *self = NULL;
2458 ModestMailOperationPrivate *priv = NULL;
2460 helper = (XFerFolderAsyncHelper *) user_data;
2461 g_return_if_fail (helper != NULL);
2463 self = helper->mail_op;
2464 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2467 priv->error = g_error_copy (err);
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2470 } else if (cancelled) {
2471 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2472 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2473 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
2474 _("Transference of %s was cancelled."),
2475 tny_folder_get_name (folder));
2478 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2481 /* Update state of new folder */
2483 tny_folder_refresh_async (new_folder, NULL, NULL, NULL);
2484 tny_folder_poke_status (new_folder);
2487 /* Notify about operation end */
2488 modest_mail_operation_notify_end (self);
2490 /* If user defined callback function was defined, call it */
2491 if (helper->user_callback) {
2493 /* This is not a GDK lock because we are a Tinymail callback
2494 * which is already GDK locked by Tinymail */
2496 /* no gdk_threads_enter (), CHECKED */
2497 helper->user_callback (self, new_folder, helper->user_data);
2498 /* no gdk_threads_leave () , CHECKED */
2502 g_object_unref (helper->mail_op);
2503 g_slice_free (XFerFolderAsyncHelper, helper);
2508 * This function checks if the new name is a valid name for our local
2509 * folders account. The new name could not be the same than then name
2510 * of any of the mandatory local folders
2512 * We can not rely on tinymail because tinymail does not check the
2513 * name of the virtual folders that the account could have in the case
2514 * that we're doing a rename (because it directly calls Camel which
2515 * knows nothing about our virtual folders).
2517 * In the case of an actual copy/move (i.e. move/copy a folder between
2518 * accounts) tinymail uses the tny_folder_store_create_account which
2519 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
2520 * checks the new name of the folder, so this call in that case
2521 * wouldn't be needed. *But* NOTE that if tinymail changes its
2522 * implementation (if folder transfers within the same account is no
2523 * longer implemented as a rename) this call will allow Modest to work
2526 * If the new name is not valid, this function will set the status to
2527 * failed and will set also an error in the mail operation
2530 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
2531 TnyFolderStore *into,
2532 const gchar *new_name)
2534 if (TNY_IS_ACCOUNT (into) &&
2535 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
2536 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
2538 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2539 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2540 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
2541 _CS("ckdg_ib_folder_already_exists"));
2548 modest_mail_operation_xfer_folder (ModestMailOperation *self,
2550 TnyFolderStore *parent,
2551 gboolean delete_original,
2552 XferFolderAsyncUserCallback user_callback,
2555 ModestMailOperationPrivate *priv = NULL;
2556 ModestTnyFolderRules parent_rules = 0, rules;
2557 XFerFolderAsyncHelper *helper = NULL;
2558 const gchar *folder_name = NULL;
2559 const gchar *error_msg;
2561 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2562 g_return_if_fail (TNY_IS_FOLDER (folder));
2563 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
2565 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2566 folder_name = tny_folder_get_name (folder);
2568 /* Set the error msg */
2569 error_msg = _("mail_in_ui_folder_move_target_error");
2571 /* Get account and set it into mail_operation */
2572 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2573 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2574 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2576 /* Get folder rules */
2577 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2578 if (TNY_IS_FOLDER (parent))
2579 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2581 /* Apply operation constraints */
2582 if ((gpointer) parent == (gpointer) folder ||
2583 (!TNY_IS_FOLDER_STORE (parent)) ||
2584 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2587 } else if (TNY_IS_FOLDER (parent) &&
2588 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2592 } else if (TNY_IS_FOLDER (parent) &&
2593 TNY_IS_FOLDER_STORE (folder) &&
2594 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2595 TNY_FOLDER_STORE (folder))) {
2596 /* Do not move a parent into a child */
2598 } else if (TNY_IS_FOLDER_STORE (parent) &&
2599 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2600 /* Check that the new folder name is not used by any
2603 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2604 /* Check that the new folder name is not used by any
2605 special local folder */
2608 /* Create the helper */
2609 helper = g_slice_new0 (XFerFolderAsyncHelper);
2610 helper->mail_op = g_object_ref (self);
2611 helper->user_callback = user_callback;
2612 helper->user_data = user_data;
2614 /* Move/Copy folder */
2615 modest_mail_operation_notify_start (self);
2616 tny_folder_copy_async (folder,
2618 tny_folder_get_name (folder),
2621 transfer_folder_status_cb,
2627 /* Set status failed and set an error */
2628 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2629 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2630 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2633 /* Call the user callback if exists */
2635 user_callback (self, NULL, user_data);
2637 /* Notify the queue */
2638 modest_mail_operation_notify_end (self);
2642 modest_mail_operation_rename_folder (ModestMailOperation *self,
2645 XferFolderAsyncUserCallback user_callback,
2648 ModestMailOperationPrivate *priv;
2649 ModestTnyFolderRules rules;
2650 XFerFolderAsyncHelper *helper;
2652 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2653 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2654 g_return_if_fail (name);
2656 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2658 /* Get account and set it into mail_operation */
2659 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2660 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2662 /* Check folder rules */
2663 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2664 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2666 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2669 TnyFolderStore *into;
2671 into = tny_folder_get_folder_store (folder);
2673 /* Check that the new folder name is not used by any
2674 special local folder */
2675 if (new_name_valid_if_local_account (priv, into, name)) {
2676 /* Create the helper */
2677 helper = g_slice_new0 (XFerFolderAsyncHelper);
2678 helper->mail_op = g_object_ref(self);
2679 helper->user_callback = user_callback;
2680 helper->user_data = user_data;
2682 /* Rename. Camel handles folder subscription/unsubscription */
2683 modest_mail_operation_notify_start (self);
2684 tny_folder_copy_async (folder, into, name, TRUE,
2686 transfer_folder_status_cb,
2688 g_object_unref (into);
2690 g_object_unref (into);
2697 /* Set status failed and set an error */
2698 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2699 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2700 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2701 _("FIXME: unable to rename"));
2704 user_callback (self, NULL, user_data);
2706 /* Notify about operation end */
2707 modest_mail_operation_notify_end (self);
2710 /* ******************************************************************* */
2711 /* ************************** MSG ACTIONS ************************* */
2712 /* ******************************************************************* */
2715 modest_mail_operation_find_msg (ModestMailOperation *self,
2717 const gchar *msg_uid,
2718 gboolean progress_feedback,
2719 GetMsgAsyncUserCallback user_callback,
2722 GetMsgInfo *helper = NULL;
2723 ModestMailOperationPrivate *priv;
2725 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2726 g_return_if_fail (msg_uid != NULL);
2728 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2729 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2733 /* Check memory low */
2734 if (_check_memory_low (self)) {
2736 user_callback (self, NULL, FALSE, NULL, priv->error, user_data);
2737 modest_mail_operation_notify_end (self);
2741 /* Get account and set it into mail_operation */
2742 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2744 /* Check for cached messages */
2745 if (progress_feedback) {
2746 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2748 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2751 /* Create the helper */
2752 helper = g_slice_new0 (GetMsgInfo);
2753 helper->header = NULL;
2754 helper->mail_op = g_object_ref (self);
2755 helper->user_callback = user_callback;
2756 helper->user_data = user_data;
2757 helper->destroy_notify = NULL;
2758 helper->last_total_bytes = 0;
2759 helper->sum_total_bytes = 0;
2760 helper->total_bytes = 0;
2761 helper->more_msgs = NULL;
2762 helper->get_parts = NULL;
2765 modest_mail_operation_notify_start (self);
2767 /* notify about the start of the operation */
2768 ModestMailOperationState *state;
2769 state = modest_mail_operation_clone_state (self);
2772 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2774 g_slice_free (ModestMailOperationState, state);
2776 tny_folder_find_msg_async (folder, msg_uid, get_msg_async_cb, get_msg_status_cb, helper);
2780 modest_mail_operation_get_msg (ModestMailOperation *self,
2782 gboolean progress_feedback,
2783 GetMsgAsyncUserCallback user_callback,
2786 GetMsgInfo *helper = NULL;
2788 ModestMailOperationPrivate *priv;
2790 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2791 g_return_if_fail (TNY_IS_HEADER (header));
2793 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2794 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2798 /* Check memory low */
2799 if (_check_memory_low (self)) {
2801 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2802 modest_mail_operation_notify_end (self);
2806 /* Get account and set it into mail_operation */
2807 folder = tny_header_get_folder (header);
2808 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2810 /* Check for cached messages */
2811 if (progress_feedback) {
2812 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2813 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2815 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2817 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2820 /* Create the helper */
2821 helper = g_slice_new0 (GetMsgInfo);
2822 helper->header = g_object_ref (header);
2823 helper->mail_op = g_object_ref (self);
2824 helper->user_callback = user_callback;
2825 helper->user_data = user_data;
2826 helper->destroy_notify = NULL;
2827 helper->last_total_bytes = 0;
2828 helper->sum_total_bytes = 0;
2829 helper->total_bytes = tny_header_get_message_size (header);
2830 helper->more_msgs = NULL;
2831 helper->get_parts = NULL;
2834 modest_mail_operation_notify_start (self);
2836 /* notify about the start of the operation */
2837 ModestMailOperationState *state;
2838 state = modest_mail_operation_clone_state (self);
2841 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2843 g_slice_free (ModestMailOperationState, state);
2845 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2847 g_object_unref (G_OBJECT (folder));
2851 modest_mail_operation_get_msg_and_parts (ModestMailOperation *self,
2854 gboolean progress_feedback,
2855 GetMsgAsyncUserCallback user_callback,
2858 GetMsgInfo *helper = NULL;
2860 ModestMailOperationPrivate *priv;
2862 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2863 g_return_if_fail (TNY_IS_HEADER (header));
2865 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2866 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2870 /* Check memory low */
2871 if (_check_memory_low (self)) {
2873 user_callback (self, header, FALSE, NULL, priv->error, user_data);
2874 modest_mail_operation_notify_end (self);
2878 /* Get account and set it into mail_operation */
2879 folder = tny_header_get_folder (header);
2880 if (folder == NULL && MODEST_IS_MSG_VIEW_WINDOW (priv->source)) {
2881 const gchar *acc_name;
2882 acc_name = modest_window_get_active_account (MODEST_WINDOW (priv->source));
2883 priv->account = modest_tny_account_store_get_server_account
2884 (modest_runtime_get_account_store (),
2886 TNY_ACCOUNT_TYPE_STORE);
2887 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (priv->account),
2888 modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (priv->source)));
2890 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2893 /* Check for cached messages */
2894 if (progress_feedback) {
2895 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2896 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2898 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2900 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
2903 /* Create the helper */
2904 helper = g_slice_new0 (GetMsgInfo);
2905 helper->header = g_object_ref (header);
2906 helper->mail_op = g_object_ref (self);
2907 helper->user_callback = user_callback;
2908 helper->user_data = user_data;
2909 helper->destroy_notify = NULL;
2910 helper->last_total_bytes = 0;
2911 helper->sum_total_bytes = 0;
2912 helper->total_bytes = tny_header_get_message_size (header);
2913 helper->more_msgs = NULL;
2914 helper->get_parts = tny_list_create_iterator (parts);
2917 modest_mail_operation_notify_start (self);
2919 /* notify about the start of the operation */
2920 ModestMailOperationState *state;
2921 state = modest_mail_operation_clone_state (self);
2924 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2926 g_slice_free (ModestMailOperationState, state);
2928 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2930 g_object_unref (G_OBJECT (folder));
2934 get_msg_status_cb (GObject *obj,
2938 GetMsgInfo *helper = NULL;
2940 g_return_if_fail (status != NULL);
2942 /* Show only the status information we want */
2943 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2946 helper = (GetMsgInfo *) user_data;
2947 g_return_if_fail (helper != NULL);
2949 /* Notify progress */
2950 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2951 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2955 get_msg_async_get_part_cb (TnyMimePart *self, gboolean cancelled, TnyStream *stream, GError *err, gpointer user_data)
2958 TnyFolder *folder = NULL;
2960 helper = (GetMsgInfo *) user_data;
2962 if (helper->header) {
2963 folder = tny_header_get_folder (helper->header);
2966 get_msg_async_cb (folder, cancelled, helper->msg, err, user_data);
2968 if (folder) g_object_unref (folder);
2972 get_msg_async_cb (TnyFolder *folder,
2978 GetMsgInfo *info = NULL;
2979 ModestMailOperationPrivate *priv = NULL;
2982 info = (GetMsgInfo *) user_data;
2984 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2987 if (info->more_msgs) {
2988 tny_iterator_next (info->more_msgs);
2989 finished = (tny_iterator_is_done (info->more_msgs));
2990 } else if (info->get_parts) {
2991 tny_iterator_next (info->get_parts);
2992 finished = (tny_iterator_is_done (info->get_parts));
2994 finished = (priv->done == priv->total) ? TRUE : FALSE;
2997 /* If canceled by the user, ignore the error given by Tinymail */
3001 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3003 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3004 priv->error = g_error_copy ((const GError *) err);
3006 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3008 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3009 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3010 "%s", err->message);
3012 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
3013 /* Set the success status before calling the user callback */
3014 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3017 if (info->header == NULL && msg)
3018 info->header = tny_msg_get_header (msg);
3020 /* Call the user callback */
3021 if (info->user_callback && (finished || (info->get_parts == NULL)))
3022 info->user_callback (info->mail_op, info->header, canceled,
3023 msg, err, info->user_data);
3025 /* Notify about operation end if this is the last callback */
3027 /* Free user data */
3028 if (info->destroy_notify)
3029 info->destroy_notify (info->user_data);
3031 /* Notify about operation end */
3032 modest_mail_operation_notify_end (info->mail_op);
3036 g_object_unref (info->msg);
3037 if (info->more_msgs)
3038 g_object_unref (info->more_msgs);
3040 g_object_unref (info->header);
3041 g_object_unref (info->mail_op);
3042 g_slice_free (GetMsgInfo, info);
3043 } else if (info->get_parts) {
3044 CamelStream *null_stream;
3045 TnyStream *tny_null_stream;
3048 if (info->msg == NULL && msg != NULL)
3049 info->msg = g_object_ref (msg);
3051 null_stream = camel_stream_null_new ();
3052 tny_null_stream = tny_camel_stream_new (null_stream);
3054 part = TNY_MIME_PART (tny_iterator_get_current (info->get_parts));
3055 tny_mime_part_decode_to_stream_async (part, tny_null_stream,
3056 get_msg_async_get_part_cb,
3059 g_object_unref (tny_null_stream);
3060 g_object_unref (part);
3062 } else if (info->more_msgs) {
3063 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
3064 TnyFolder *folder = tny_header_get_folder (header);
3066 g_object_unref (info->header);
3067 info->header = g_object_ref (header);
3069 /* Retrieve the next message */
3070 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
3072 g_object_unref (header);
3073 g_object_unref (folder);
3075 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
3080 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
3081 TnyList *header_list,
3082 GetMsgAsyncUserCallback user_callback,
3084 GDestroyNotify notify)
3086 ModestMailOperationPrivate *priv = NULL;
3088 TnyIterator *iter = NULL;
3089 gboolean has_uncached_messages;
3091 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3093 /* Init mail operation */
3094 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3095 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3097 priv->total = tny_list_get_length(header_list);
3099 /* Check memory low */
3100 if (_check_memory_low (self)) {
3101 if (user_callback) {
3102 TnyHeader *header = NULL;
3105 if (tny_list_get_length (header_list) > 0) {
3106 iter = tny_list_create_iterator (header_list);
3107 header = (TnyHeader *) tny_iterator_get_current (iter);
3108 g_object_unref (iter);
3110 user_callback (self, header, FALSE, NULL, priv->error, user_data);
3112 g_object_unref (header);
3116 /* Notify about operation end */
3117 modest_mail_operation_notify_end (self);
3121 /* Check uncached messages */
3122 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
3123 !has_uncached_messages && !tny_iterator_is_done (iter);
3124 tny_iterator_next (iter)) {
3127 header = (TnyHeader *) tny_iterator_get_current (iter);
3128 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
3129 has_uncached_messages = TRUE;
3130 g_object_unref (header);
3132 g_object_unref (iter);
3133 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
3135 /* Get account and set it into mail_operation */
3136 if (tny_list_get_length (header_list) >= 1) {
3137 TnyIterator *iterator = tny_list_create_iterator (header_list);
3138 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
3140 TnyFolder *folder = tny_header_get_folder (header);
3142 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3143 g_object_unref (folder);
3145 g_object_unref (header);
3147 g_object_unref (iterator);
3150 msg_list_size = compute_message_list_size (header_list, 0);
3152 modest_mail_operation_notify_start (self);
3153 iter = tny_list_create_iterator (header_list);
3154 if (!tny_iterator_is_done (iter)) {
3155 /* notify about the start of the operation */
3156 ModestMailOperationState *state;
3157 state = modest_mail_operation_clone_state (self);
3160 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3163 GetMsgInfo *msg_info = NULL;
3164 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3165 TnyFolder *folder = tny_header_get_folder (header);
3167 /* Create the message info */
3168 msg_info = g_slice_new0 (GetMsgInfo);
3169 msg_info->mail_op = g_object_ref (self);
3170 msg_info->header = g_object_ref (header);
3171 msg_info->more_msgs = g_object_ref (iter);
3172 msg_info->user_callback = user_callback;
3173 msg_info->user_data = user_data;
3174 msg_info->destroy_notify = notify;
3175 msg_info->last_total_bytes = 0;
3176 msg_info->sum_total_bytes = 0;
3177 msg_info->total_bytes = msg_list_size;
3178 msg_info->msg = NULL;
3180 /* The callback will call it per each header */
3181 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
3183 /* Free and go on */
3184 g_object_unref (header);
3185 g_object_unref (folder);
3186 g_slice_free (ModestMailOperationState, state);
3188 g_object_unref (iter);
3193 remove_msgs_async_cb (TnyFolder *folder,
3199 const gchar *account_name;
3200 TnyAccount *account;
3201 ModestProtocolType account_proto = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
3202 ModestMailOperation *self;
3203 ModestMailOperationPrivate *priv;
3204 ModestProtocolRegistry *protocol_registry;
3205 SyncFolderHelper *helper;
3207 self = (ModestMailOperation *) user_data;
3208 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3209 protocol_registry = modest_runtime_get_protocol_registry ();
3211 if (canceled || err) {
3212 /* If canceled by the user, ignore the error given by Tinymail */
3214 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3216 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
3217 priv->error = g_error_copy ((const GError *) err);
3218 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
3221 modest_mail_operation_notify_end (self);
3222 g_object_unref (self);
3226 account = modest_tny_folder_get_account (folder);
3227 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3228 account_proto = modest_tny_account_get_protocol_type (account);
3229 g_object_unref (account);
3231 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_proto)) {
3232 if (modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3242 helper = g_slice_new0 (SyncFolderHelper);
3243 helper->mail_op = g_object_ref (self);
3244 helper->user_callback = NULL;
3245 helper->user_data = NULL;
3248 tny_folder_sync_async(folder, expunge, sync_folder_finish_callback, NULL, helper);
3250 /* Remove the extra reference */
3251 g_object_unref (self);
3255 modest_mail_operation_remove_msgs (ModestMailOperation *self,
3257 gboolean remove_to_trash /*ignored*/)
3259 TnyFolder *folder = NULL;
3260 ModestMailOperationPrivate *priv;
3261 TnyIterator *iter = NULL;
3262 TnyHeader *header = NULL;
3263 TnyList *remove_headers = NULL;
3264 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
3265 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
3267 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3268 g_return_if_fail (TNY_IS_LIST (headers));
3270 if (remove_to_trash)
3271 g_warning ("remove to trash is not implemented");
3273 if (tny_list_get_length(headers) == 0) {
3274 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
3275 goto cleanup; /* nothing to do */
3278 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3280 /* Get folder from first header and sync it */
3281 iter = tny_list_create_iterator (headers);
3282 header = TNY_HEADER (tny_iterator_get_current (iter));
3283 g_object_unref (iter);
3285 folder = tny_header_get_folder (header);
3286 if (!TNY_IS_FOLDER(folder)) {
3287 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
3291 /* Use the merged folder if we're removing messages from outbox */
3292 if (modest_tny_folder_is_local_folder (folder)) {
3293 ModestTnyLocalFoldersAccount *local_account;
3295 local_account = (ModestTnyLocalFoldersAccount *)
3296 modest_tny_account_store_get_local_folders_account (accstore);
3297 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
3298 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3299 g_object_unref (folder);
3300 folder = modest_tny_local_folders_account_get_merged_outbox (local_account);
3302 g_object_unref (local_account);
3305 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
3306 TnyIterator *headers_iter = tny_list_create_iterator (headers);
3308 while (!tny_iterator_is_done (headers_iter)) {
3309 TnyTransportAccount *traccount = NULL;
3310 TnyHeader *hdr = NULL;
3312 hdr = TNY_HEADER (tny_iterator_get_current (headers_iter));
3313 traccount = modest_tny_account_store_get_transport_account_from_outbox_header (accstore,
3316 ModestTnySendQueueStatus status;
3317 ModestTnySendQueue *send_queue;
3319 send_queue = modest_runtime_get_send_queue(traccount, TRUE);
3320 if (TNY_IS_SEND_QUEUE (send_queue)) {
3323 msg_id = modest_tny_send_queue_get_msg_id (hdr);
3324 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
3325 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
3326 if (G_UNLIKELY (remove_headers == NULL))
3327 remove_headers = tny_simple_list_new ();
3328 tny_list_append(remove_headers, G_OBJECT(hdr));
3332 g_object_unref(traccount);
3334 g_object_unref(hdr);
3335 tny_iterator_next (headers_iter);
3337 g_object_unref(headers_iter);
3340 /* Get account and set it into mail_operation */
3341 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
3342 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
3343 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3345 if (!remove_headers)
3346 remove_headers = g_object_ref (headers);
3348 /* Notify messages are "read" */
3349 iter = tny_list_create_iterator (remove_headers);
3350 while (!tny_iterator_is_done (iter)) {
3354 header = TNY_HEADER (tny_iterator_get_current (iter));
3355 msg_uid = modest_tny_folder_get_header_unique_id (header);
3357 modest_platform_emit_msg_read_changed_signal (msg_uid, TRUE);
3360 g_object_unref (header);
3361 tny_iterator_next (iter);
3363 g_object_unref (iter);
3365 /* remove message from folder */
3366 modest_mail_operation_notify_start (self);
3367 tny_folder_remove_msgs_async (folder, remove_headers, remove_msgs_async_cb,
3368 NULL, g_object_ref (self));
3372 g_object_unref (remove_headers);
3374 g_object_unref (header);
3376 g_object_unref (folder);
3380 notify_progress_of_multiple_messages (ModestMailOperation *self,
3382 gint *last_total_bytes,
3383 gint *sum_total_bytes,
3385 gboolean increment_done)
3387 ModestMailOperationPrivate *priv;
3388 ModestMailOperationState *state;
3389 gboolean is_num_bytes = FALSE;
3391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3393 /* We know that tinymail sends us information about
3394 * transferred bytes with this particular message
3396 if (status->message)
3397 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
3399 state = modest_mail_operation_clone_state (self);
3400 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
3401 /* We know that we're in a different message when the
3402 total number of bytes to transfer is different. Of
3403 course it could fail if we're transferring messages
3404 of the same size, but this is a workarround */
3405 if (status->of_total != *last_total_bytes) {
3406 /* We need to increment the done when there is
3407 no information about each individual
3408 message, we need to do this in message
3409 transfers, and we don't do it for getting
3413 *sum_total_bytes += *last_total_bytes;
3414 *last_total_bytes = status->of_total;
3416 state->bytes_done += status->position + *sum_total_bytes;
3417 state->bytes_total = total_bytes;
3419 /* Notify the status change. Only notify about changes
3420 referred to bytes */
3421 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3425 g_slice_free (ModestMailOperationState, state);
3429 transfer_msgs_status_cb (GObject *obj,
3433 XFerMsgsAsyncHelper *helper;
3435 g_return_if_fail (status != NULL);
3437 /* Show only the status information we want */
3438 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
3441 helper = (XFerMsgsAsyncHelper *) user_data;
3442 g_return_if_fail (helper != NULL);
3444 /* Notify progress */
3445 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
3446 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
3450 transfer_msgs_sync_folder_cb (TnyFolder *self,
3455 XFerMsgsAsyncHelper *helper;
3456 /* We don't care here about the results of the
3458 helper = (XFerMsgsAsyncHelper *) user_data;
3460 /* Notify about operation end */
3461 modest_mail_operation_notify_end (helper->mail_op);
3463 /* If user defined callback function was defined, call it */
3464 if (helper->user_callback)
3465 helper->user_callback (helper->mail_op, helper->user_data);
3468 if (helper->more_msgs)
3469 g_object_unref (helper->more_msgs);
3470 if (helper->headers)
3471 g_object_unref (helper->headers);
3472 if (helper->dest_folder)
3473 g_object_unref (helper->dest_folder);
3474 if (helper->mail_op)
3475 g_object_unref (helper->mail_op);
3476 g_slice_free (XFerMsgsAsyncHelper, helper);
3480 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
3482 XFerMsgsAsyncHelper *helper;
3483 ModestMailOperation *self;
3484 ModestMailOperationPrivate *priv;
3485 gboolean finished = TRUE;
3487 helper = (XFerMsgsAsyncHelper *) user_data;
3488 self = helper->mail_op;
3490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3493 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3495 priv->error = g_error_copy (err);
3497 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3498 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
3499 if (helper->more_msgs) {
3500 /* We'll transfer the next message in the list */
3501 tny_iterator_next (helper->more_msgs);
3502 if (!tny_iterator_is_done (helper->more_msgs)) {
3503 GObject *next_header;
3504 g_object_unref (helper->headers);
3505 helper->headers = tny_simple_list_new ();
3506 next_header = tny_iterator_get_current (helper->more_msgs);
3507 tny_list_append (helper->headers, next_header);
3508 g_object_unref (next_header);
3514 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3519 /* Synchronize the source folder contents. This should
3520 be done by tinymail but the camel_folder_sync it's
3521 actually disabled in transfer_msgs_thread_clean
3522 because it's supposed to cause hangs */
3523 tny_folder_sync_async (folder, helper->delete,
3524 transfer_msgs_sync_folder_cb,
3527 /* Transfer more messages */
3528 tny_folder_transfer_msgs_async (folder,
3530 helper->dest_folder,
3533 transfer_msgs_status_cb,
3538 /* Computes the size of the messages the headers in the list belongs
3539 to. If num_elements is different from 0 then it only takes into
3540 account the first num_elements for the calculation */
3542 compute_message_list_size (TnyList *headers,
3546 guint size = 0, element = 0;
3548 /* If num_elements is not valid then take all into account */
3549 if ((num_elements <= 0) || (num_elements > tny_list_get_length (headers)))
3550 num_elements = tny_list_get_length (headers);
3552 iter = tny_list_create_iterator (headers);
3553 while (!tny_iterator_is_done (iter) && element < num_elements) {
3554 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
3555 size += tny_header_get_message_size (header);
3556 g_object_unref (header);
3557 tny_iterator_next (iter);
3560 g_object_unref (iter);
3566 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
3569 gboolean delete_original,
3570 XferMsgsAsyncUserCallback user_callback,
3573 ModestMailOperationPrivate *priv = NULL;
3574 TnyIterator *iter = NULL;
3575 TnyFolder *src_folder = NULL;
3576 XFerMsgsAsyncHelper *helper = NULL;
3577 TnyHeader *header = NULL;
3578 ModestTnyFolderRules rules = 0;
3579 TnyAccount *dst_account = NULL;
3580 gboolean leave_on_server;
3581 ModestMailOperationState *state;
3582 ModestProtocolRegistry *protocol_registry;
3583 ModestProtocolType account_protocol;
3585 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
3586 g_return_if_fail (headers && TNY_IS_LIST (headers));
3587 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
3589 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3590 protocol_registry = modest_runtime_get_protocol_registry ();
3592 priv->total = tny_list_get_length (headers);
3594 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3595 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3597 /* Apply folder rules */
3598 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
3599 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3600 /* Set status failed and set an error */
3601 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3602 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3603 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
3604 _CS("ckct_ib_unable_to_paste_here"));
3605 /* Notify the queue */
3606 modest_mail_operation_notify_end (self);
3610 /* Get source folder */
3611 iter = tny_list_create_iterator (headers);
3612 header = TNY_HEADER (tny_iterator_get_current (iter));
3614 src_folder = tny_header_get_folder (header);
3615 g_object_unref (header);
3617 g_object_unref (iter);
3619 if (src_folder == NULL) {
3620 /* Notify the queue */
3621 modest_mail_operation_notify_end (self);
3623 g_warning ("%s: cannot find folder from header", __FUNCTION__);
3628 /* Check folder source and destination */
3629 if (src_folder == folder) {
3630 /* Set status failed and set an error */
3631 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3632 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3633 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
3634 _("mail_in_ui_folder_copy_target_error"));
3636 /* Notify the queue */
3637 modest_mail_operation_notify_end (self);
3640 g_object_unref (src_folder);
3644 /* Create the helper */
3645 helper = g_slice_new0 (XFerMsgsAsyncHelper);
3646 helper->mail_op = g_object_ref(self);
3647 helper->dest_folder = g_object_ref(folder);
3648 helper->user_callback = user_callback;
3649 helper->user_data = user_data;
3650 helper->last_total_bytes = 0;
3651 helper->sum_total_bytes = 0;
3652 helper->total_bytes = compute_message_list_size (headers, 0);
3654 /* Get account and set it into mail_operation */
3655 priv->account = modest_tny_folder_get_account (src_folder);
3656 dst_account = modest_tny_folder_get_account (folder);
3658 if (priv->account == dst_account) {
3659 /* Transfer all messages at once using the fast
3660 * method. Note that depending on the server this
3661 * might not be that fast, and might not be
3662 * user-cancellable either */
3663 helper->headers = g_object_ref (headers);
3664 helper->more_msgs = NULL;
3666 /* Transfer messages one by one so the user can cancel
3669 helper->headers = tny_simple_list_new ();
3670 helper->more_msgs = tny_list_create_iterator (headers);
3671 hdr = tny_iterator_get_current (helper->more_msgs);
3672 tny_list_append (helper->headers, hdr);
3673 g_object_unref (hdr);
3676 /* If leave_on_server is set to TRUE then don't use
3677 delete_original, we always pass FALSE. This is because
3678 otherwise tinymail will try to sync the source folder and
3679 this could cause an error if we're offline while
3680 transferring an already downloaded message from a POP
3682 account_protocol = modest_tny_account_get_protocol_type (priv->account);
3683 if (modest_protocol_registry_protocol_type_has_leave_on_server (protocol_registry, account_protocol)) {
3684 const gchar *account_name;
3686 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
3687 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
3690 leave_on_server = FALSE;
3693 /* Do not delete messages if leave on server is TRUE */
3694 helper->delete = (leave_on_server) ? FALSE : delete_original;
3696 modest_mail_operation_notify_start (self);
3698 /* Start notifying progress */
3699 state = modest_mail_operation_clone_state (self);
3702 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3703 g_slice_free (ModestMailOperationState, state);
3705 tny_folder_transfer_msgs_async (src_folder,
3710 transfer_msgs_status_cb,
3712 g_object_unref (src_folder);
3713 g_object_unref (dst_account);
3718 on_refresh_folder (TnyFolder *folder,
3723 RefreshAsyncHelper *helper = NULL;
3724 ModestMailOperation *self = NULL;
3725 ModestMailOperationPrivate *priv = NULL;
3727 helper = (RefreshAsyncHelper *) user_data;
3728 self = helper->mail_op;
3729 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3731 g_return_if_fail(priv!=NULL);
3734 priv->error = g_error_copy (error);
3735 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3740 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
3741 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3742 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
3743 _("Error trying to refresh the contents of %s"),
3744 tny_folder_get_name (folder));
3748 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3751 /* Call user defined callback, if it exists */
3752 if (helper->user_callback) {
3754 /* This is not a GDK lock because we are a Tinymail callback and
3755 * Tinymail already acquires the Gdk lock */
3756 helper->user_callback (self, folder, helper->user_data);
3760 g_slice_free (RefreshAsyncHelper, helper);
3762 /* Notify about operation end */
3763 modest_mail_operation_notify_end (self);
3764 g_object_unref(self);
3768 on_refresh_folder_status_update (GObject *obj,
3772 RefreshAsyncHelper *helper = NULL;
3773 ModestMailOperation *self = NULL;
3774 ModestMailOperationPrivate *priv = NULL;
3775 ModestMailOperationState *state;
3777 g_return_if_fail (user_data != NULL);
3778 g_return_if_fail (status != NULL);
3780 /* Show only the status information we want */
3781 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
3784 helper = (RefreshAsyncHelper *) user_data;
3785 self = helper->mail_op;
3786 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
3788 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3790 priv->done = status->position;
3791 priv->total = status->of_total;
3793 state = modest_mail_operation_clone_state (self);
3795 /* This is not a GDK lock because we are a Tinymail callback and
3796 * Tinymail already acquires the Gdk lock */
3797 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
3799 g_slice_free (ModestMailOperationState, state);
3803 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3805 RefreshAsyncUserCallback user_callback,
3808 ModestMailOperationPrivate *priv = NULL;
3809 RefreshAsyncHelper *helper = NULL;
3811 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3813 /* Check memory low */
3814 if (_check_memory_low (self)) {
3816 user_callback (self, folder, user_data);
3817 /* Notify about operation end */
3818 modest_mail_operation_notify_end (self);
3822 /* Get account and set it into mail_operation */
3823 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3824 priv->account = modest_tny_folder_get_account (folder);
3825 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3827 /* Create the helper */
3828 helper = g_slice_new0 (RefreshAsyncHelper);
3829 helper->mail_op = g_object_ref(self);
3830 helper->user_callback = user_callback;
3831 helper->user_data = user_data;
3833 modest_mail_operation_notify_start (self);
3835 /* notify that the operation was started */
3836 ModestMailOperationState *state;
3837 state = modest_mail_operation_clone_state (self);
3840 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3842 g_slice_free (ModestMailOperationState, state);
3844 tny_folder_refresh_async (folder,
3846 on_refresh_folder_status_update,
3851 run_queue_notify_and_destroy (RunQueueHelper *helper,
3852 ModestMailOperationStatus status)
3854 ModestMailOperationPrivate *priv;
3857 if (helper->error_handler &&
3858 g_signal_handler_is_connected (helper->queue, helper->error_handler))
3859 g_signal_handler_disconnect (helper->queue, helper->error_handler);
3860 if (helper->start_handler &&
3861 g_signal_handler_is_connected (helper->queue, helper->start_handler))
3862 g_signal_handler_disconnect (helper->queue, helper->start_handler);
3863 if (helper->stop_handler &&
3864 g_signal_handler_is_connected (helper->queue, helper->stop_handler))
3865 g_signal_handler_disconnect (helper->queue, helper->stop_handler);
3868 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->self);
3869 priv->status = status;
3872 modest_mail_operation_notify_end (helper->self);
3875 g_object_unref (helper->queue);
3876 g_object_unref (helper->self);
3877 g_slice_free (RunQueueHelper, helper);
3881 run_queue_stop (ModestTnySendQueue *queue,
3884 RunQueueHelper *helper;
3886 g_debug ("%s sending queue stopped", __FUNCTION__);
3888 helper = (RunQueueHelper *) user_data;
3889 run_queue_notify_and_destroy (helper, MODEST_MAIL_OPERATION_STATUS_SUCCESS);
3893 modest_mail_operation_run_queue (ModestMailOperation *self,
3894 ModestTnySendQueue *queue)
3896 ModestMailOperationPrivate *priv;
3897 RunQueueHelper *helper;
3899 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3900 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3901 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3903 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3904 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3905 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3907 /* Create the helper */
3908 helper = g_slice_new0 (RunQueueHelper);
3909 helper->queue = g_object_ref (queue);
3910 helper->self = g_object_ref (self);
3911 helper->stop_handler = g_signal_connect (queue, "queue-stop",
3912 G_CALLBACK (run_queue_stop),
3915 /* Notify operation has started */
3916 modest_mail_operation_notify_start (self);
3917 g_debug ("%s, run queue started", __FUNCTION__);
3921 queue_wakeup_callback (ModestTnySendQueue *queue,
3926 ModestMailOperation *mail_op;
3927 ModestMailOperationPrivate *priv;
3929 mail_op = (ModestMailOperation *) userdata;
3930 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3932 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3933 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (queue));
3936 modest_mail_operation_notify_end (mail_op);
3937 g_object_unref (mail_op);
3941 modest_mail_operation_queue_wakeup (ModestMailOperation *self,
3942 ModestTnySendQueue *queue)
3944 ModestMailOperationPrivate *priv;
3946 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3947 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3948 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3950 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3951 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3952 priv->op_type = MODEST_MAIL_OPERATION_TYPE_QUEUE_WAKEUP;
3954 g_object_ref (self);
3956 modest_tny_send_queue_wakeup (queue, queue_wakeup_callback, self);
3957 modest_mail_operation_notify_start (self);
3961 shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata)
3963 ModestMailOperation *self = (ModestMailOperation *) userdata;
3964 ModestMailOperationPrivate *priv;
3966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3967 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3968 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3970 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3972 modest_mail_operation_notify_end (self);
3973 g_object_unref (self);
3977 modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store)
3979 ModestMailOperationPrivate *priv;
3981 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3982 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store));
3983 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3985 modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ());
3987 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3988 priv->account = NULL;
3989 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN;
3991 modest_mail_operation_notify_start (self);
3992 g_object_ref (self);
3993 modest_tny_account_store_shutdown (account_store, shutdown_callback, self);
3997 sync_folder_finish_callback (TnyFolder *self,
4003 ModestMailOperationPrivate *priv;
4004 SyncFolderHelper *helper;
4006 helper = (SyncFolderHelper *) user_data;
4007 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (helper->mail_op);
4009 /* If canceled by the user, ignore the error given by Tinymail */
4011 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
4013 /* If the operation was a sync then the status is
4014 failed, but if it's part of another operation then
4015 just set it as finished with errors */
4016 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER)
4017 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4019 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
4020 priv->error = g_error_copy ((const GError *) err);
4021 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
4023 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4027 if (helper->user_callback)
4028 helper->user_callback (helper->mail_op, self, helper->user_data);
4030 modest_mail_operation_notify_end (helper->mail_op);
4033 g_object_unref (helper->mail_op);
4034 g_slice_free (SyncFolderHelper, helper);
4038 modest_mail_operation_sync_folder (ModestMailOperation *self,
4041 SyncFolderCallback callback,
4044 ModestMailOperationPrivate *priv;
4045 SyncFolderHelper *helper;
4047 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
4048 g_return_if_fail (TNY_IS_FOLDER (folder));
4049 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
4051 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
4052 priv->account = modest_tny_folder_get_account (folder);
4053 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
4056 helper = g_slice_new0 (SyncFolderHelper);
4057 helper->mail_op = g_object_ref (self);
4058 helper->user_callback = callback;
4059 helper->user_data = user_data;
4061 modest_mail_operation_notify_start (self);
4062 tny_folder_sync_async (folder, expunge,
4063 (TnyFolderCallback) sync_folder_finish_callback,
4068 modest_mail_operation_notify_start (ModestMailOperation *self)
4070 ModestMailOperationPrivate *priv = NULL;
4072 g_return_if_fail (self);
4074 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4076 /* Ensure that all the fields are filled correctly */
4077 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
4079 /* Notify the observers about the mail operation. We do not
4080 wrapp this emission because we assume that this function is
4081 always called from within the main lock */
4082 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
4087 * It's used by the mail operation queue to notify the observers
4088 * attached to that signal that the operation finished. We need to use
4089 * that because tinymail does not give us the progress of a given
4090 * operation when it finishes (it directly calls the operation
4094 modest_mail_operation_notify_end (ModestMailOperation *self)
4096 ModestMailOperationPrivate *priv = NULL;
4098 g_return_if_fail (self);
4100 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4102 /* Notify the observers about the mail operation end. We do
4103 not wrapp this emission because we assume that this
4104 function is always called from within the main lock */
4105 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
4107 /* Remove the error user data */
4108 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
4109 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
4113 modest_mail_operation_get_account (ModestMailOperation *self)
4115 ModestMailOperationPrivate *priv = NULL;
4117 g_return_val_if_fail (self, NULL);
4119 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4121 return (priv->account) ? g_object_ref (priv->account) : NULL;
4125 modest_mail_operation_noop (ModestMailOperation *self)
4127 ModestMailOperationPrivate *priv = NULL;
4129 g_return_if_fail (self);
4131 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4132 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
4133 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
4137 /* This mail operation does nothing actually */
4138 modest_mail_operation_notify_start (self);
4139 modest_mail_operation_notify_end (self);
4144 modest_mail_operation_to_string (ModestMailOperation *self)
4146 const gchar *type, *status, *account_id;
4147 ModestMailOperationPrivate *priv = NULL;
4149 g_return_val_if_fail (self, NULL);
4151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
4153 /* new operations don't have anything interesting */
4154 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
4155 return g_strdup_printf ("%p <new operation>", self);
4157 switch (priv->op_type) {
4158 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
4159 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE: type= "SEND-AND-RECEIVE"; break;
4160 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
4161 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
4162 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
4163 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
4164 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
4165 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
4166 case MODEST_MAIL_OPERATION_TYPE_SHUTDOWN: type= "SHUTDOWN"; break;
4167 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
4168 default: type = "UNEXPECTED"; break;
4171 switch (priv->status) {
4172 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
4173 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
4174 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
4175 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
4176 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
4177 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
4178 default: status= "UNEXPECTED"; break;
4181 account_id = priv->account ? tny_account_get_id (priv->account) : "";
4183 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
4184 priv->done, priv->total,
4185 priv->error && priv->error->message ? priv->error->message : "");
4189 * Once the mail operations were objects this will be no longer
4190 * needed. I don't like it, but we need it for the moment
4193 _check_memory_low (ModestMailOperation *mail_op)
4195 if (modest_platform_check_memory_low (NULL, FALSE)) {
4196 ModestMailOperationPrivate *priv;
4198 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
4199 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
4200 g_set_error (&(priv->error),
4201 MODEST_MAIL_OPERATION_ERROR,
4202 MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY,
4203 "Not enough memory to complete the operation");