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-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include "modest-account-mgr-helpers.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-send-queue.h>
51 #include <modest-runtime.h>
52 #include "modest-text-utils.h"
53 #include "modest-tny-msg.h"
54 #include "modest-tny-folder.h"
55 #include "modest-tny-account-store.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-marshal.h"
58 #include "modest-error.h"
59 #include "modest-mail-operation.h"
60 #include <modest-count-stream.h>
61 #include <libgnomevfs/gnome-vfs.h>
62 #include "modest-utils.h"
63 #include "modest-debug.h"
68 * Remove all these #ifdef stuff when the tinymail's idle calls become
71 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
73 /* 'private'/'protected' functions */
74 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
75 static void modest_mail_operation_init (ModestMailOperation *obj);
76 static void modest_mail_operation_finalize (GObject *obj);
78 static void get_msg_async_cb (TnyFolder *folder,
84 static void get_msg_status_cb (GObject *obj,
88 static void modest_mail_operation_notify_start (ModestMailOperation *self);
89 static void modest_mail_operation_notify_end (ModestMailOperation *self);
91 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
93 gint *last_total_bytes,
94 gint *sum_total_bytes,
96 gboolean increment_done);
98 static guint compute_message_list_size (TnyList *headers);
100 static guint compute_message_array_size (GPtrArray *headers);
102 static int compare_headers_by_date (gconstpointer a,
105 enum _ModestMailOperationSignals
107 PROGRESS_CHANGED_SIGNAL,
108 OPERATION_STARTED_SIGNAL,
109 OPERATION_FINISHED_SIGNAL,
113 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
114 struct _ModestMailOperationPrivate {
120 ErrorCheckingUserCallback error_checking;
121 gpointer error_checking_user_data;
122 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
123 ModestMailOperationStatus status;
124 ModestMailOperationTypeOperation op_type;
127 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
128 MODEST_TYPE_MAIL_OPERATION, \
129 ModestMailOperationPrivate))
131 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
132 priv->status = new_status;\
137 GetMsgAsyncUserCallback user_callback;
139 TnyIterator *more_msgs;
141 ModestMailOperation *mail_op;
142 GDestroyNotify destroy_notify;
143 gint last_total_bytes;
144 gint sum_total_bytes;
148 typedef struct _RefreshAsyncHelper {
149 ModestMailOperation *mail_op;
150 RefreshAsyncUserCallback user_callback;
152 } RefreshAsyncHelper;
154 typedef struct _XFerMsgsAsyncHelper
156 ModestMailOperation *mail_op;
158 TnyIterator *more_msgs;
159 TnyFolder *dest_folder;
160 XferMsgsAsyncUserCallback user_callback;
163 gint last_total_bytes;
164 gint sum_total_bytes;
166 } XFerMsgsAsyncHelper;
168 typedef struct _XFerFolderAsyncHelper
170 ModestMailOperation *mail_op;
171 XferFolderAsyncUserCallback user_callback;
173 } XFerFolderAsyncHelper;
175 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
179 static void modest_mail_operation_create_msg (ModestMailOperation *self,
180 const gchar *from, const gchar *to,
181 const gchar *cc, const gchar *bcc,
182 const gchar *subject, const gchar *plain_body,
183 const gchar *html_body, const GList *attachments_list,
184 const GList *images_list,
185 TnyHeaderFlags priority_flags,
186 ModestMailOperationCreateMsgCallback callback,
189 static gboolean idle_notify_queue (gpointer data);
192 ModestMailOperation *mail_op;
200 GList *attachments_list;
202 TnyHeaderFlags priority_flags;
203 ModestMailOperationCreateMsgCallback callback;
209 ModestMailOperation *mail_op;
211 ModestMailOperationCreateMsgCallback callback;
216 static GObjectClass *parent_class = NULL;
218 static guint signals[NUM_SIGNALS] = {0};
221 modest_mail_operation_get_type (void)
223 static GType my_type = 0;
225 static const GTypeInfo my_info = {
226 sizeof(ModestMailOperationClass),
227 NULL, /* base init */
228 NULL, /* base finalize */
229 (GClassInitFunc) modest_mail_operation_class_init,
230 NULL, /* class finalize */
231 NULL, /* class data */
232 sizeof(ModestMailOperation),
234 (GInstanceInitFunc) modest_mail_operation_init,
237 my_type = g_type_register_static (G_TYPE_OBJECT,
238 "ModestMailOperation",
245 modest_mail_operation_class_init (ModestMailOperationClass *klass)
247 GObjectClass *gobject_class;
248 gobject_class = (GObjectClass*) klass;
250 parent_class = g_type_class_peek_parent (klass);
251 gobject_class->finalize = modest_mail_operation_finalize;
253 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
256 * ModestMailOperation::progress-changed
257 * @self: the #MailOperation that emits the signal
258 * @user_data: user data set when the signal handler was connected
260 * Emitted when the progress of a mail operation changes
262 signals[PROGRESS_CHANGED_SIGNAL] =
263 g_signal_new ("progress-changed",
264 G_TYPE_FROM_CLASS (gobject_class),
266 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
268 g_cclosure_marshal_VOID__POINTER,
269 G_TYPE_NONE, 1, G_TYPE_POINTER);
273 * This signal is issued whenever a mail operation starts, and
274 * starts mean when the tinymail operation is issued. This
275 * means that it could happen that something wrong happens and
276 * the tinymail function is never called. In this situation a
277 * operation-finished will be issued without any
280 signals[OPERATION_STARTED_SIGNAL] =
281 g_signal_new ("operation-started",
282 G_TYPE_FROM_CLASS (gobject_class),
284 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
286 g_cclosure_marshal_VOID__VOID,
291 * This signal is issued whenever a mail operation
292 * finishes. Note that this signal could be issued without any
293 * previous "operation-started" signal, because this last one
294 * is only issued when the tinymail operation is successfully
297 signals[OPERATION_FINISHED_SIGNAL] =
298 g_signal_new ("operation-finished",
299 G_TYPE_FROM_CLASS (gobject_class),
301 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
303 g_cclosure_marshal_VOID__VOID,
308 modest_mail_operation_init (ModestMailOperation *obj)
310 ModestMailOperationPrivate *priv;
312 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
314 priv->account = NULL;
315 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
316 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
321 priv->error_checking = NULL;
322 priv->error_checking_user_data = NULL;
326 modest_mail_operation_finalize (GObject *obj)
328 ModestMailOperationPrivate *priv;
330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
335 g_error_free (priv->error);
339 g_object_unref (priv->source);
343 g_object_unref (priv->account);
344 priv->account = NULL;
348 G_OBJECT_CLASS(parent_class)->finalize (obj);
352 modest_mail_operation_new (GObject *source)
354 ModestMailOperation *obj;
355 ModestMailOperationPrivate *priv;
357 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
358 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
361 priv->source = g_object_ref(source);
367 modest_mail_operation_new_with_error_handling (GObject *source,
368 ErrorCheckingUserCallback error_handler,
370 ErrorCheckingUserDataDestroyer error_handler_destroyer)
372 ModestMailOperation *obj;
373 ModestMailOperationPrivate *priv;
375 obj = modest_mail_operation_new (source);
376 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
378 g_return_val_if_fail (error_handler != NULL, obj);
379 priv->error_checking = error_handler;
380 priv->error_checking_user_data = user_data;
381 priv->error_checking_user_data_destroyer = error_handler_destroyer;
387 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
389 ModestMailOperationPrivate *priv;
391 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
394 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
396 /* Call the user callback */
397 if (priv->error_checking != NULL)
398 priv->error_checking (self, priv->error_checking_user_data);
402 ModestMailOperationTypeOperation
403 modest_mail_operation_get_type_operation (ModestMailOperation *self)
405 ModestMailOperationPrivate *priv;
407 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
408 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
410 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
412 return priv->op_type;
416 modest_mail_operation_is_mine (ModestMailOperation *self,
419 ModestMailOperationPrivate *priv;
421 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
424 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
425 if (priv->source == NULL) return FALSE;
427 return priv->source == me;
431 modest_mail_operation_get_source (ModestMailOperation *self)
433 ModestMailOperationPrivate *priv;
435 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
438 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
440 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
444 return (priv->source) ? g_object_ref (priv->source) : NULL;
447 ModestMailOperationStatus
448 modest_mail_operation_get_status (ModestMailOperation *self)
450 ModestMailOperationPrivate *priv;
452 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
453 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
454 MODEST_MAIL_OPERATION_STATUS_INVALID);
456 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
458 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
459 return MODEST_MAIL_OPERATION_STATUS_INVALID;
466 modest_mail_operation_get_error (ModestMailOperation *self)
468 ModestMailOperationPrivate *priv;
470 g_return_val_if_fail (self, NULL);
471 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
473 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
476 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
484 modest_mail_operation_cancel (ModestMailOperation *self)
486 ModestMailOperationPrivate *priv;
487 gboolean canceled = FALSE;
489 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
494 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
496 /* Cancel the mail operation */
497 g_return_val_if_fail (priv->account, FALSE);
498 tny_account_cancel (priv->account);
500 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
501 ModestTnySendQueue *queue;
502 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
504 /* Cancel the sending of the following next messages */
505 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
512 modest_mail_operation_get_task_done (ModestMailOperation *self)
514 ModestMailOperationPrivate *priv;
516 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
519 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
524 modest_mail_operation_get_task_total (ModestMailOperation *self)
526 ModestMailOperationPrivate *priv;
528 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
531 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
536 modest_mail_operation_is_finished (ModestMailOperation *self)
538 ModestMailOperationPrivate *priv;
539 gboolean retval = FALSE;
541 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
546 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
547 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
548 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
549 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
559 * Creates an image of the current state of a mail operation, the
560 * caller must free it
562 static ModestMailOperationState *
563 modest_mail_operation_clone_state (ModestMailOperation *self)
565 ModestMailOperationState *state;
566 ModestMailOperationPrivate *priv;
568 /* FIXME: this should be fixed properly
570 * in some cases, priv was NULL, so checking here to
573 g_return_val_if_fail (self, NULL);
574 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
575 g_return_val_if_fail (priv, NULL);
580 state = g_slice_new (ModestMailOperationState);
582 state->status = priv->status;
583 state->op_type = priv->op_type;
584 state->done = priv->done;
585 state->total = priv->total;
586 state->finished = modest_mail_operation_is_finished (self);
587 state->bytes_done = 0;
588 state->bytes_total = 0;
593 /* ******************************************************************* */
594 /* ************************** SEND ACTIONS ************************* */
595 /* ******************************************************************* */
598 modest_mail_operation_send_mail (ModestMailOperation *self,
599 TnyTransportAccount *transport_account,
602 TnySendQueue *send_queue = NULL;
603 ModestMailOperationPrivate *priv;
605 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
606 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
607 g_return_if_fail (msg && TNY_IS_MSG (msg));
609 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
611 /* Get account and set it into mail_operation */
612 priv->account = g_object_ref (transport_account);
613 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
617 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
618 if (!TNY_IS_SEND_QUEUE(send_queue)) {
619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
621 "modest: could not find send queue for account\n");
622 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
623 modest_mail_operation_notify_end (self);
626 /* Add the msg to the queue */
627 modest_mail_operation_notify_start (self);
629 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
630 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue), FALSE);
632 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
633 modest_mail_operation_notify_end (self);
640 idle_create_msg_cb (gpointer idle_data)
642 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
644 /* This is a GDK lock because we are an idle callback and
645 * info->callback can contain Gtk+ code */
647 gdk_threads_enter (); /* CHECKED */
648 info->callback (info->mail_op, info->msg, info->userdata);
650 g_object_unref (info->mail_op);
652 g_object_unref (info->msg);
653 g_slice_free (CreateMsgIdleInfo, info);
654 gdk_threads_leave (); /* CHECKED */
660 create_msg_thread (gpointer thread_data)
662 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
663 TnyMsg *new_msg = NULL;
664 ModestMailOperationPrivate *priv;
666 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
667 if (info->html_body == NULL) {
668 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
669 info->bcc, info->subject, info->plain_body,
670 info->attachments_list);
672 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
673 info->bcc, info->subject, info->html_body,
674 info->plain_body, info->attachments_list,
681 /* Set priority flags in message */
682 header = tny_msg_get_header (new_msg);
683 tny_header_set_flag (header, info->priority_flags);
685 /* Set attachment flags in message */
686 if (info->attachments_list != NULL)
687 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
689 g_object_unref (G_OBJECT(header));
691 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
692 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
693 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
694 "modest: failed to create a new msg\n");
702 g_free (info->plain_body);
703 g_free (info->html_body);
704 g_free (info->subject);
705 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
706 g_list_free (info->attachments_list);
707 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
708 g_list_free (info->images_list);
710 if (info->callback) {
711 CreateMsgIdleInfo *idle_info;
712 idle_info = g_slice_new0 (CreateMsgIdleInfo);
713 idle_info->mail_op = g_object_ref (info->mail_op);
714 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
715 idle_info->callback = info->callback;
716 idle_info->userdata = info->userdata;
717 g_idle_add (idle_create_msg_cb, idle_info);
719 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
722 g_object_unref (info->mail_op);
723 g_slice_free (CreateMsgInfo, info);
724 if (new_msg) g_object_unref(new_msg);
730 modest_mail_operation_create_msg (ModestMailOperation *self,
731 const gchar *from, const gchar *to,
732 const gchar *cc, const gchar *bcc,
733 const gchar *subject, const gchar *plain_body,
734 const gchar *html_body,
735 const GList *attachments_list,
736 const GList *images_list,
737 TnyHeaderFlags priority_flags,
738 ModestMailOperationCreateMsgCallback callback,
741 CreateMsgInfo *info = NULL;
743 info = g_slice_new0 (CreateMsgInfo);
744 info->mail_op = g_object_ref (self);
746 info->from = g_strdup (from);
747 info->to = g_strdup (to);
748 info->cc = g_strdup (cc);
749 info->bcc = g_strdup (bcc);
750 info->subject = g_strdup (subject);
751 info->plain_body = g_strdup (plain_body);
752 info->html_body = g_strdup (html_body);
753 info->attachments_list = g_list_copy ((GList *) attachments_list);
754 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
755 info->images_list = g_list_copy ((GList *) images_list);
756 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
757 info->priority_flags = priority_flags;
759 info->callback = callback;
760 info->userdata = userdata;
762 g_thread_create (create_msg_thread, info, FALSE, NULL);
767 TnyTransportAccount *transport_account;
772 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
776 ModestMailOperationPrivate *priv = NULL;
777 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
778 TnyFolder *draft_folder = NULL;
779 TnyFolder *outbox_folder = NULL;
780 TnyHeader *header = NULL;
787 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
790 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
791 modest_mail_operation_notify_end (self);
795 /* Call mail operation */
796 modest_mail_operation_send_mail (self, info->transport_account, msg);
798 if (info->draft_msg != NULL) {
799 TnyFolder *folder = NULL;
800 TnyFolder *src_folder = NULL;
801 TnyFolderType folder_type;
802 TnyTransportAccount *transport_account = NULL;
804 /* To remove the old mail from its source folder, we need to get the
805 * transport account of the original draft message (the transport account
806 * might have been changed by the user) */
807 header = tny_msg_get_header (info->draft_msg);
808 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
809 modest_runtime_get_account_store(), header);
810 if (transport_account == NULL)
811 transport_account = g_object_ref(info->transport_account);
812 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
813 TNY_FOLDER_TYPE_DRAFTS);
814 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
815 TNY_FOLDER_TYPE_OUTBOX);
816 g_object_unref(transport_account);
819 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
823 if (!outbox_folder) {
824 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
829 folder = tny_msg_get_folder (info->draft_msg);
830 if (folder == NULL) goto end;
831 folder_type = modest_tny_folder_guess_folder_type (folder);
833 if (folder_type == TNY_FOLDER_TYPE_INVALID)
834 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
836 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
837 src_folder = outbox_folder;
839 src_folder = draft_folder;
841 /* Note: This can fail (with a warning) if the message is not really already in a folder,
842 * because this function requires it to have a UID. */
843 tny_folder_remove_msg (src_folder, header, NULL);
845 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
846 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
848 g_object_unref (folder);
853 g_object_unref (header);
857 g_object_unref (info->draft_msg);
859 g_object_unref (draft_folder);
861 g_object_unref (outbox_folder);
862 if (info->transport_account)
863 g_object_unref (info->transport_account);
864 g_slice_free (SendNewMailInfo, info);
868 modest_mail_operation_send_new_mail (ModestMailOperation *self,
869 TnyTransportAccount *transport_account,
871 const gchar *from, const gchar *to,
872 const gchar *cc, const gchar *bcc,
873 const gchar *subject, const gchar *plain_body,
874 const gchar *html_body,
875 const GList *attachments_list,
876 const GList *images_list,
877 TnyHeaderFlags priority_flags)
879 ModestMailOperationPrivate *priv = NULL;
880 SendNewMailInfo *info;
882 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
883 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
886 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
887 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
888 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
890 /* Check parametters */
892 /* Set status failed and set an error */
893 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
894 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
895 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
896 _("Error trying to send a mail. You need to set at least one recipient"));
899 info = g_slice_new0 (SendNewMailInfo);
900 info->transport_account = transport_account;
901 if (transport_account)
902 g_object_ref (transport_account);
903 info->draft_msg = draft_msg;
905 g_object_ref (draft_msg);
908 modest_mail_operation_notify_start (self);
909 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
910 attachments_list, images_list, priority_flags,
911 modest_mail_operation_send_new_mail_cb, info);
917 TnyTransportAccount *transport_account;
919 SaveToDraftstCallback callback;
923 ModestMailOperation *mailop;
924 } SaveToDraftsAddMsgInfo;
927 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
932 ModestMailOperationPrivate *priv = NULL;
933 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
935 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
938 g_warning ("%s: priv->error != NULL", __FUNCTION__);
939 g_error_free(priv->error);
942 priv->error = (err == NULL) ? NULL : g_error_copy(err);
944 if ((!priv->error) && (info->draft_msg != NULL)) {
945 TnyHeader *header = tny_msg_get_header (info->draft_msg);
946 TnyFolder *src_folder = tny_header_get_folder (header);
948 /* Remove the old draft */
949 tny_folder_remove_msg (src_folder, header, NULL);
951 /* Synchronize to expunge and to update the msg counts */
952 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
953 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
955 g_object_unref (G_OBJECT(header));
956 g_object_unref (G_OBJECT(src_folder));
960 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
962 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
964 /* Call the user callback */
966 info->callback (info->mailop, info->msg, info->user_data);
968 if (info->transport_account)
969 g_object_unref (G_OBJECT(info->transport_account));
971 g_object_unref (G_OBJECT (info->draft_msg));
973 g_object_unref (G_OBJECT(info->drafts));
975 g_object_unref (G_OBJECT (info->msg));
977 modest_mail_operation_notify_end (info->mailop);
978 g_object_unref(info->mailop);
979 g_slice_free (SaveToDraftsAddMsgInfo, info);
984 TnyTransportAccount *transport_account;
986 SaveToDraftstCallback callback;
991 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
995 TnyFolder *drafts = NULL;
996 ModestMailOperationPrivate *priv = NULL;
997 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
999 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1002 if (!(priv->error)) {
1003 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1004 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1005 "modest: failed to create a new msg\n");
1008 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1009 TNY_FOLDER_TYPE_DRAFTS);
1010 if (!drafts && !(priv->error)) {
1011 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1012 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1013 "modest: failed to create a new msg\n");
1018 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1019 cb_info->transport_account = g_object_ref(info->transport_account);
1020 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1021 cb_info->callback = info->callback;
1022 cb_info->user_data = info->user_data;
1023 cb_info->drafts = g_object_ref(drafts);
1024 cb_info->msg = g_object_ref(msg);
1025 cb_info->mailop = g_object_ref(self);
1026 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1029 /* Call the user callback */
1030 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1032 info->callback (self, msg, info->user_data);
1033 modest_mail_operation_notify_end (self);
1037 g_object_unref (G_OBJECT(drafts));
1038 if (info->draft_msg)
1039 g_object_unref (G_OBJECT (info->draft_msg));
1040 if (info->transport_account)
1041 g_object_unref (G_OBJECT(info->transport_account));
1042 g_slice_free (SaveToDraftsInfo, info);
1046 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1047 TnyTransportAccount *transport_account,
1049 const gchar *from, const gchar *to,
1050 const gchar *cc, const gchar *bcc,
1051 const gchar *subject, const gchar *plain_body,
1052 const gchar *html_body,
1053 const GList *attachments_list,
1054 const GList *images_list,
1055 TnyHeaderFlags priority_flags,
1056 SaveToDraftstCallback callback,
1059 ModestMailOperationPrivate *priv = NULL;
1060 SaveToDraftsInfo *info = NULL;
1062 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1063 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1065 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1067 /* Get account and set it into mail_operation */
1068 priv->account = g_object_ref (transport_account);
1069 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1071 info = g_slice_new0 (SaveToDraftsInfo);
1072 info->transport_account = g_object_ref (transport_account);
1073 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1074 info->callback = callback;
1075 info->user_data = user_data;
1077 modest_mail_operation_notify_start (self);
1078 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1079 attachments_list, images_list, priority_flags,
1080 modest_mail_operation_save_to_drafts_cb, info);
1085 ModestMailOperation *mail_op;
1086 TnyMimePart *mime_part;
1088 GetMimePartSizeCallback callback;
1090 } GetMimePartSizeInfo;
1092 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1093 /* We use this folder observer to track the headers that have been
1094 * added to a folder */
1097 TnyList *new_headers;
1098 } InternalFolderObserver;
1101 GObjectClass parent;
1102 } InternalFolderObserverClass;
1104 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1106 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1107 internal_folder_observer,
1109 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1113 foreach_add_item (gpointer header, gpointer user_data)
1115 tny_list_prepend (TNY_LIST (user_data),
1116 g_object_ref (G_OBJECT (header)));
1119 /* This is the method that looks for new messages in a folder */
1121 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1123 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1125 TnyFolderChangeChanged changed;
1127 changed = tny_folder_change_get_changed (change);
1129 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1132 /* Get added headers */
1133 list = tny_simple_list_new ();
1134 tny_folder_change_get_added_headers (change, list);
1136 /* Add them to the folder observer */
1137 tny_list_foreach (list, foreach_add_item,
1138 derived->new_headers);
1140 g_object_unref (G_OBJECT (list));
1145 internal_folder_observer_init (InternalFolderObserver *self)
1147 self->new_headers = tny_simple_list_new ();
1150 internal_folder_observer_finalize (GObject *object)
1152 InternalFolderObserver *self;
1154 self = (InternalFolderObserver *) object;
1155 g_object_unref (self->new_headers);
1157 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1160 tny_folder_observer_init (TnyFolderObserverIface *iface)
1162 iface->update = internal_folder_observer_update;
1165 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1167 GObjectClass *object_class;
1169 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1170 object_class = (GObjectClass*) klass;
1171 object_class->finalize = internal_folder_observer_finalize;
1176 ModestMailOperation *mail_op;
1177 gchar *account_name;
1178 UpdateAccountCallback callback;
1183 TnyFolderObserver *inbox_observer;
1184 RetrieveAllCallback retrieve_all_cb;
1185 gboolean interactive;
1186 } UpdateAccountInfo;
1190 destroy_update_account_info (UpdateAccountInfo *info)
1192 g_free (info->account_name);
1193 g_object_unref (info->folders);
1194 g_object_unref (info->mail_op);
1195 g_slice_free (UpdateAccountInfo, info);
1199 update_account_get_msg_async_cb (TnyFolder *folder,
1205 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1207 /* Just delete the helper. Don't do anything with the new
1208 msg. There is also no need to check for errors */
1209 g_object_unref (msg_info->mail_op);
1210 g_object_unref (msg_info->header);
1211 g_slice_free (GetMsgInfo, msg_info);
1215 update_account_notify_user_and_free (UpdateAccountInfo *info,
1216 TnyList *new_headers)
1218 /* Set the account back to not busy */
1219 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (),
1220 info->account_name, FALSE);
1224 info->callback (info->mail_op, new_headers, info->user_data);
1226 /* Mail operation end */
1227 modest_mail_operation_notify_end (info->mail_op);
1231 g_object_unref (new_headers);
1232 destroy_update_account_info (info);
1236 inbox_refreshed_cb (TnyFolder *inbox,
1241 UpdateAccountInfo *info;
1242 ModestMailOperationPrivate *priv;
1243 TnyIterator *new_headers_iter;
1244 GPtrArray *new_headers_array = NULL;
1245 gint max_size, retrieve_limit, i;
1246 ModestAccountMgr *mgr;
1247 ModestAccountRetrieveType retrieve_type;
1248 TnyList *new_headers = NULL;
1249 gboolean headers_only, ignore_limit, succeeded;
1250 TnyTransportAccount *transport_account = NULL;
1252 info = (UpdateAccountInfo *) user_data;
1253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1254 mgr = modest_runtime_get_account_mgr ();
1256 if (canceled || err) {
1257 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1259 priv->error = g_error_copy (err);
1261 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1262 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1264 /* Notify the user about the error and then exit */
1265 update_account_notify_user_and_free (info, NULL);
1270 /* Try to send anyway */
1274 /* Get the message max size */
1275 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1276 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1278 max_size = G_MAXINT;
1280 max_size = max_size * KB;
1282 /* Create the new headers array. We need it to sort the
1283 new headers by date */
1284 new_headers_array = g_ptr_array_new ();
1285 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1286 while (!tny_iterator_is_done (new_headers_iter)) {
1287 TnyHeader *header = NULL;
1289 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1290 /* Apply per-message size limits */
1291 if (tny_header_get_message_size (header) < max_size)
1292 g_ptr_array_add (new_headers_array, g_object_ref (header));
1294 g_object_unref (header);
1295 tny_iterator_next (new_headers_iter);
1297 g_object_unref (new_headers_iter);
1298 tny_folder_remove_observer (inbox, info->inbox_observer);
1299 g_object_unref (info->inbox_observer);
1300 info->inbox_observer = NULL;
1302 /* Update the last updated key, even if we don't have to get new headers */
1303 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1304 if (!canceled && !err)
1305 modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
1307 if (new_headers_array->len == 0)
1310 /* Get per-account message amount retrieval limit */
1311 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1312 if (retrieve_limit == 0)
1313 retrieve_limit = G_MAXINT;
1315 /* Get per-account retrieval type */
1316 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1317 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1320 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1322 /* Ask the users if they want to retrieve all the messages
1323 even though the limit was exceeded */
1324 ignore_limit = FALSE;
1325 if (new_headers_array->len > retrieve_limit) {
1326 /* Ask the user if a callback has been specified and
1327 if the mail operation has a source (this means that
1328 was invoked by the user and not automatically by a
1330 if (info->retrieve_all_cb && priv->source)
1331 ignore_limit = info->retrieve_all_cb (priv->source,
1332 new_headers_array->len,
1336 if (!headers_only) {
1338 const gint msg_list_size = compute_message_array_size (new_headers_array);
1342 priv->total = new_headers_array->len;
1344 priv->total = MIN (new_headers_array->len, retrieve_limit);
1345 while (msg_num < priv->total) {
1346 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1347 TnyFolder *folder = tny_header_get_folder (header);
1348 GetMsgInfo *msg_info;
1350 /* Create the message info */
1351 msg_info = g_slice_new0 (GetMsgInfo);
1352 msg_info->mail_op = g_object_ref (info->mail_op);
1353 msg_info->header = g_object_ref (header);
1354 msg_info->total_bytes = msg_list_size;
1356 /* Get message in an async way */
1357 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1358 get_msg_status_cb, msg_info);
1360 g_object_unref (folder);
1366 /* Copy the headers to a list and free the array */
1367 new_headers = tny_simple_list_new ();
1368 for (i=0; i < new_headers_array->len; i++) {
1369 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1370 tny_list_append (new_headers, G_OBJECT (header));
1372 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1373 g_ptr_array_free (new_headers_array, FALSE);
1379 modest_account_mgr_set_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1380 tny_account_get_name (priv->account),
1383 /* Get the transport account */
1384 transport_account = (TnyTransportAccount *)
1385 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1386 info->account_name);
1388 if (transport_account) {
1389 ModestTnySendQueue *send_queue;
1393 send_queue = modest_runtime_get_send_queue (transport_account);
1394 g_object_unref (transport_account);
1396 /* Get outbox folder */
1397 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1398 if (outbox) { /* this could fail in some cases */
1399 num_messages = tny_folder_get_all_count (outbox);
1400 g_object_unref (outbox);
1402 g_warning ("%s: could not get outbox", __FUNCTION__);
1406 if (num_messages != 0) {
1407 /* Reenable suspended items */
1408 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1411 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1412 modest_tny_send_queue_set_requested_send_receive (MODEST_TNY_SEND_QUEUE (send_queue),
1417 /* Check if the operation was a success */
1419 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1421 /* Call the user callback and free */
1422 update_account_notify_user_and_free (info, new_headers);
1426 recurse_folders_async_cb (TnyFolderStore *folder_store,
1432 UpdateAccountInfo *info;
1433 ModestMailOperationPrivate *priv;
1435 info = (UpdateAccountInfo *) user_data;
1436 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1438 if (err || canceled) {
1439 /* If the error was previosly set by another callback
1440 don't set it again */
1442 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1444 priv->error = g_error_copy (err);
1446 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1447 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1451 /* We're not getting INBOX children if we don't want to poke all */
1452 TnyIterator *iter = tny_list_create_iterator (list);
1453 while (!tny_iterator_is_done (iter)) {
1454 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1456 /* Add to the list of all folders */
1457 tny_list_append (info->folders, (GObject *) folder);
1459 if (info->poke_all) {
1460 TnyList *folders = tny_simple_list_new ();
1461 /* Add pending call */
1462 info->pending_calls++;
1464 tny_folder_store_get_folders_async (folder, folders, NULL,
1465 recurse_folders_async_cb,
1467 g_object_unref (folders);
1470 g_object_unref (G_OBJECT (folder));
1472 tny_iterator_next (iter);
1474 g_object_unref (G_OBJECT (iter));
1477 /* Remove my own pending call */
1478 info->pending_calls--;
1480 /* This means that we have all the folders */
1481 if (info->pending_calls == 0) {
1482 TnyIterator *iter_all_folders;
1483 TnyFolder *inbox = NULL;
1485 /* If there was any error do not continue */
1487 update_account_notify_user_and_free (info, NULL);
1491 iter_all_folders = tny_list_create_iterator (info->folders);
1493 /* Do a poke status over all folders */
1494 while (!tny_iterator_is_done (iter_all_folders) &&
1495 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1496 TnyFolder *folder = NULL;
1498 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1500 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1501 /* Get a reference to the INBOX */
1502 inbox = g_object_ref (folder);
1504 /* Issue a poke status over the folder */
1506 tny_folder_poke_status (folder);
1509 /* Free and go to next */
1510 g_object_unref (folder);
1511 tny_iterator_next (iter_all_folders);
1513 g_object_unref (iter_all_folders);
1515 /* Refresh the INBOX */
1517 /* Refresh the folder. Our observer receives
1518 * the new emails during folder refreshes, so
1519 * we can use observer->new_headers
1521 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1522 tny_folder_add_observer (inbox, info->inbox_observer);
1524 /* Refresh the INBOX */
1525 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1526 g_object_unref (inbox);
1528 /* We could not perform the inbox refresh but
1529 we'll try to send mails anyway */
1530 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1536 modest_mail_operation_update_account (ModestMailOperation *self,
1537 const gchar *account_name,
1539 gboolean interactive,
1540 RetrieveAllCallback retrieve_all_cb,
1541 UpdateAccountCallback callback,
1544 UpdateAccountInfo *info = NULL;
1545 ModestMailOperationPrivate *priv = NULL;
1546 ModestTnyAccountStore *account_store = NULL;
1548 ModestMailOperationState *state;
1550 /* Init mail operation */
1551 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1554 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1555 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1557 /* Get the store account */
1558 account_store = modest_runtime_get_account_store ();
1560 modest_tny_account_store_get_server_account (account_store,
1562 TNY_ACCOUNT_TYPE_STORE);
1564 /* The above function could return NULL */
1565 if (!priv->account) {
1566 /* Check if the operation was a success */
1567 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1568 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1570 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1572 /* Call the user callback */
1574 callback (self, NULL, user_data);
1576 /* Notify about operation end */
1577 modest_mail_operation_notify_end (self);
1582 /* We have once seen priv->account getting finalized during this code,
1583 * therefore adding a reference (bug #82296) */
1585 g_object_ref (priv->account);
1587 /* Create the helper object */
1588 info = g_slice_new0 (UpdateAccountInfo);
1589 info->pending_calls = 1;
1590 info->folders = tny_simple_list_new ();
1591 info->mail_op = g_object_ref (self);
1592 info->poke_all = poke_all;
1593 info->interactive = interactive;
1594 info->account_name = g_strdup (account_name);
1595 info->callback = callback;
1596 info->user_data = user_data;
1597 info->retrieve_all_cb = retrieve_all_cb;
1599 /* Set account busy */
1600 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1601 modest_mail_operation_notify_start (self);
1603 /* notify about the start of the operation */
1604 state = modest_mail_operation_clone_state (self);
1608 /* Start notifying progress */
1609 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1610 g_slice_free (ModestMailOperationState, state);
1612 /* Get all folders and continue in the callback */
1613 folders = tny_simple_list_new ();
1614 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1616 recurse_folders_async_cb,
1618 g_object_unref (folders);
1620 g_object_unref (priv->account);
1625 * Used to notify the queue from the main
1626 * loop. We call it inside an idle call to achieve that
1629 idle_notify_queue (gpointer data)
1631 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1633 gdk_threads_enter ();
1634 modest_mail_operation_notify_end (mail_op);
1635 gdk_threads_leave ();
1636 g_object_unref (mail_op);
1642 compare_headers_by_date (gconstpointer a,
1645 TnyHeader **header1, **header2;
1646 time_t sent1, sent2;
1648 header1 = (TnyHeader **) a;
1649 header2 = (TnyHeader **) b;
1651 sent1 = tny_header_get_date_sent (*header1);
1652 sent2 = tny_header_get_date_sent (*header2);
1654 /* We want the most recent ones (greater time_t) at the
1663 /* ******************************************************************* */
1664 /* ************************** STORE ACTIONS ************************* */
1665 /* ******************************************************************* */
1668 ModestMailOperation *mail_op;
1669 CreateFolderUserCallback callback;
1675 create_folder_cb (TnyFolderStore *parent_folder,
1677 TnyFolder *new_folder,
1681 ModestMailOperationPrivate *priv;
1682 CreateFolderInfo *info;
1684 info = (CreateFolderInfo *) user_data;
1685 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1687 if (canceled || err) {
1688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1690 priv->error = g_error_copy (err);
1692 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1693 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1699 /* The user will unref the new_folder */
1701 info->callback (info->mail_op, parent_folder,
1702 new_folder, info->user_data);
1704 /* Notify about operation end */
1705 modest_mail_operation_notify_end (info->mail_op);
1708 g_object_unref (info->mail_op);
1709 g_slice_free (CreateFolderInfo, info);
1713 modest_mail_operation_create_folder (ModestMailOperation *self,
1714 TnyFolderStore *parent,
1716 CreateFolderUserCallback callback,
1719 ModestMailOperationPrivate *priv;
1721 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1722 g_return_if_fail (name);
1724 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1725 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1726 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1727 g_object_ref (parent) :
1728 modest_tny_folder_get_account (TNY_FOLDER (parent));
1730 /* Check for already existing folder */
1731 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1732 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1733 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1734 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1735 _CS("ckdg_ib_folder_already_exists"));
1739 if (TNY_IS_FOLDER (parent)) {
1740 /* Check folder rules */
1741 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1742 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1743 /* Set status failed and set an error */
1744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1746 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1747 _("mail_in_ui_folder_create_error"));
1751 if (!strcmp (name, " ") || strchr (name, '/')) {
1752 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1753 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1754 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1755 _("mail_in_ui_folder_create_error"));
1759 CreateFolderInfo *info;
1761 info = g_slice_new0 (CreateFolderInfo);
1762 info->mail_op = g_object_ref (self);
1763 info->callback = callback;
1764 info->user_data = user_data;
1766 modest_mail_operation_notify_start (self);
1768 /* Create the folder */
1769 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1772 /* Call the user callback anyway */
1774 callback (self, parent, NULL, user_data);
1775 /* Notify about operation end */
1776 modest_mail_operation_notify_end (self);
1781 modest_mail_operation_remove_folder (ModestMailOperation *self,
1783 gboolean remove_to_trash)
1785 ModestMailOperationPrivate *priv;
1786 ModestTnyFolderRules rules;
1788 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1789 g_return_if_fail (TNY_IS_FOLDER (folder));
1791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1793 /* Check folder rules */
1794 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1795 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1796 /* Set status failed and set an error */
1797 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1798 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1799 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1800 _("mail_in_ui_folder_delete_error"));
1804 /* Get the account */
1805 priv->account = modest_tny_folder_get_account (folder);
1806 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1808 /* Delete folder or move to trash */
1809 if (remove_to_trash) {
1810 TnyFolder *trash_folder = NULL;
1811 trash_folder = modest_tny_account_get_special_folder (priv->account,
1812 TNY_FOLDER_TYPE_TRASH);
1813 /* TODO: error_handling */
1815 modest_mail_operation_notify_start (self);
1816 modest_mail_operation_xfer_folder (self, folder,
1817 TNY_FOLDER_STORE (trash_folder),
1819 g_object_unref (trash_folder);
1821 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1824 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1826 modest_mail_operation_notify_start (self);
1827 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1828 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1831 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1833 g_object_unref (parent);
1835 g_warning ("%s: could not get parent folder", __FUNCTION__);
1839 /* Notify about operation end */
1840 modest_mail_operation_notify_end (self);
1844 transfer_folder_status_cb (GObject *obj,
1848 ModestMailOperation *self;
1849 ModestMailOperationPrivate *priv;
1850 ModestMailOperationState *state;
1851 XFerFolderAsyncHelper *helper;
1853 g_return_if_fail (status != NULL);
1855 /* Show only the status information we want */
1856 if (status->code != TNY_FOLDER_STATUS_CODE_COPY_FOLDER)
1859 helper = (XFerFolderAsyncHelper *) user_data;
1860 g_return_if_fail (helper != NULL);
1862 self = helper->mail_op;
1863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1865 priv->done = status->position;
1866 priv->total = status->of_total;
1868 state = modest_mail_operation_clone_state (self);
1870 /* This is not a GDK lock because we are a Tinymail callback
1871 * which is already GDK locked by Tinymail */
1873 /* no gdk_threads_enter (), CHECKED */
1875 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1877 /* no gdk_threads_leave (), CHECKED */
1879 g_slice_free (ModestMailOperationState, state);
1884 transfer_folder_cb (TnyFolder *folder,
1886 TnyFolderStore *into,
1887 TnyFolder *new_folder,
1891 XFerFolderAsyncHelper *helper;
1892 ModestMailOperation *self = NULL;
1893 ModestMailOperationPrivate *priv = NULL;
1895 helper = (XFerFolderAsyncHelper *) user_data;
1896 g_return_if_fail (helper != NULL);
1898 self = helper->mail_op;
1899 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1902 priv->error = g_error_copy (err);
1904 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1905 } else if (cancelled) {
1906 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1907 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1908 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1909 _("Transference of %s was cancelled."),
1910 tny_folder_get_name (folder));
1913 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1916 /* Notify about operation end */
1917 modest_mail_operation_notify_end (self);
1919 /* If user defined callback function was defined, call it */
1920 if (helper->user_callback) {
1922 /* This is not a GDK lock because we are a Tinymail callback
1923 * which is already GDK locked by Tinymail */
1925 /* no gdk_threads_enter (), CHECKED */
1926 helper->user_callback (self, new_folder, helper->user_data);
1927 /* no gdk_threads_leave () , CHECKED */
1931 g_object_unref (helper->mail_op);
1932 g_slice_free (XFerFolderAsyncHelper, helper);
1937 * This function checks if the new name is a valid name for our local
1938 * folders account. The new name could not be the same than then name
1939 * of any of the mandatory local folders
1941 * We can not rely on tinymail because tinymail does not check the
1942 * name of the virtual folders that the account could have in the case
1943 * that we're doing a rename (because it directly calls Camel which
1944 * knows nothing about our virtual folders).
1946 * In the case of an actual copy/move (i.e. move/copy a folder between
1947 * accounts) tinymail uses the tny_folder_store_create_account which
1948 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1949 * checks the new name of the folder, so this call in that case
1950 * wouldn't be needed. *But* NOTE that if tinymail changes its
1951 * implementation (if folder transfers within the same account is no
1952 * longer implemented as a rename) this call will allow Modest to work
1955 * If the new name is not valid, this function will set the status to
1956 * failed and will set also an error in the mail operation
1959 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1960 TnyFolderStore *into,
1961 const gchar *new_name)
1963 if (TNY_IS_ACCOUNT (into) &&
1964 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1965 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1967 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1968 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1969 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1970 _CS("ckdg_ib_folder_already_exists"));
1977 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1979 TnyFolderStore *parent,
1980 gboolean delete_original,
1981 XferFolderAsyncUserCallback user_callback,
1984 ModestMailOperationPrivate *priv = NULL;
1985 ModestTnyFolderRules parent_rules = 0, rules;
1986 XFerFolderAsyncHelper *helper = NULL;
1987 const gchar *folder_name = NULL;
1988 const gchar *error_msg;
1990 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1991 g_return_if_fail (TNY_IS_FOLDER (folder));
1992 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1994 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1995 folder_name = tny_folder_get_name (folder);
1997 /* Set the error msg */
1998 error_msg = _("mail_in_ui_folder_move_target_error");
2000 /* Get account and set it into mail_operation */
2001 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2002 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2003 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2005 /* Get folder rules */
2006 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2007 if (TNY_IS_FOLDER (parent))
2008 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
2010 /* Apply operation constraints */
2011 if ((gpointer) parent == (gpointer) folder ||
2012 (!TNY_IS_FOLDER_STORE (parent)) ||
2013 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
2016 } else if (TNY_IS_FOLDER (parent) &&
2017 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
2021 } else if (TNY_IS_FOLDER (parent) &&
2022 TNY_IS_FOLDER_STORE (folder) &&
2023 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
2024 TNY_FOLDER_STORE (folder))) {
2025 /* Do not move a parent into a child */
2027 } else if (TNY_IS_FOLDER_STORE (parent) &&
2028 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
2029 /* Check that the new folder name is not used by any
2032 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
2033 /* Check that the new folder name is not used by any
2034 special local folder */
2037 /* Create the helper */
2038 helper = g_slice_new0 (XFerFolderAsyncHelper);
2039 helper->mail_op = g_object_ref (self);
2040 helper->user_callback = user_callback;
2041 helper->user_data = user_data;
2043 /* Move/Copy folder */
2044 modest_mail_operation_notify_start (self);
2045 tny_folder_copy_async (folder,
2047 tny_folder_get_name (folder),
2050 transfer_folder_status_cb,
2056 /* Set status failed and set an error */
2057 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2058 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2059 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2062 /* Call the user callback if exists */
2064 user_callback (self, NULL, user_data);
2066 /* Notify the queue */
2067 modest_mail_operation_notify_end (self);
2071 modest_mail_operation_rename_folder (ModestMailOperation *self,
2074 XferFolderAsyncUserCallback user_callback,
2077 ModestMailOperationPrivate *priv;
2078 ModestTnyFolderRules rules;
2079 XFerFolderAsyncHelper *helper;
2081 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2082 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2083 g_return_if_fail (name);
2085 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2087 /* Get account and set it into mail_operation */
2088 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2089 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2091 /* Check folder rules */
2092 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2093 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2095 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2098 TnyFolderStore *into;
2100 into = tny_folder_get_folder_store (folder);
2102 /* Check that the new folder name is not used by any
2103 special local folder */
2104 if (new_name_valid_if_local_account (priv, into, name)) {
2105 /* Create the helper */
2106 helper = g_slice_new0 (XFerFolderAsyncHelper);
2107 helper->mail_op = g_object_ref(self);
2108 helper->user_callback = user_callback;
2109 helper->user_data = user_data;
2111 /* Rename. Camel handles folder subscription/unsubscription */
2112 modest_mail_operation_notify_start (self);
2113 tny_folder_copy_async (folder, into, name, TRUE,
2115 transfer_folder_status_cb,
2120 g_object_unref (into);
2125 /* Set status failed and set an error */
2126 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2127 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2128 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2129 _("FIXME: unable to rename"));
2132 user_callback (self, NULL, user_data);
2134 /* Notify about operation end */
2135 modest_mail_operation_notify_end (self);
2138 /* ******************************************************************* */
2139 /* ************************** MSG ACTIONS ************************* */
2140 /* ******************************************************************* */
2143 modest_mail_operation_get_msg (ModestMailOperation *self,
2145 GetMsgAsyncUserCallback user_callback,
2148 GetMsgInfo *helper = NULL;
2150 ModestMailOperationPrivate *priv;
2152 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2153 g_return_if_fail (TNY_IS_HEADER (header));
2155 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2156 folder = tny_header_get_folder (header);
2158 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2162 /* Get account and set it into mail_operation */
2163 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2165 /* Check for cached messages */
2166 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2167 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2169 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2171 /* Create the helper */
2172 helper = g_slice_new0 (GetMsgInfo);
2173 helper->header = g_object_ref (header);
2174 helper->mail_op = g_object_ref (self);
2175 helper->user_callback = user_callback;
2176 helper->user_data = user_data;
2177 helper->destroy_notify = NULL;
2178 helper->last_total_bytes = 0;
2179 helper->sum_total_bytes = 0;
2180 helper->total_bytes = tny_header_get_message_size (header);
2182 modest_mail_operation_notify_start (self);
2184 /* notify about the start of the operation */
2185 ModestMailOperationState *state;
2186 state = modest_mail_operation_clone_state (self);
2189 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2192 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2194 g_object_unref (G_OBJECT (folder));
2198 get_msg_status_cb (GObject *obj,
2202 GetMsgInfo *helper = NULL;
2204 g_return_if_fail (status != NULL);
2206 /* Show only the status information we want */
2207 if (status->code != TNY_FOLDER_STATUS_CODE_GET_MSG)
2210 helper = (GetMsgInfo *) user_data;
2211 g_return_if_fail (helper != NULL);
2213 /* Notify progress */
2214 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2215 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2219 get_msg_async_cb (TnyFolder *folder,
2225 GetMsgInfo *info = NULL;
2226 ModestMailOperationPrivate *priv = NULL;
2229 info = (GetMsgInfo *) user_data;
2231 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2234 if (info->more_msgs) {
2235 tny_iterator_next (info->more_msgs);
2236 finished = (tny_iterator_is_done (info->more_msgs));
2238 finished = (priv->done == priv->total) ? TRUE : FALSE;
2241 /* If canceled by the user, ignore the error given by Tinymail */
2242 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED || canceled) {
2246 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2248 priv->error = g_error_copy ((const GError *) err);
2249 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2252 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2253 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2256 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2257 /* Set the success status before calling the user callback */
2258 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2262 /* Call the user callback */
2263 if (info->user_callback)
2264 info->user_callback (info->mail_op, info->header, canceled,
2265 msg, err, info->user_data);
2267 /* Notify about operation end if this is the last callback */
2269 /* Free user data */
2270 if (info->destroy_notify)
2271 info->destroy_notify (info->user_data);
2273 /* Notify about operation end */
2274 modest_mail_operation_notify_end (info->mail_op);
2277 if (info->more_msgs)
2278 g_object_unref (info->more_msgs);
2279 g_object_unref (info->header);
2280 g_object_unref (info->mail_op);
2281 g_slice_free (GetMsgInfo, info);
2282 } else if (info->more_msgs) {
2283 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2284 TnyFolder *folder = tny_header_get_folder (header);
2286 g_object_unref (info->header);
2287 info->header = g_object_ref (header);
2289 /* Retrieve the next message */
2290 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2292 g_object_unref (header);
2293 g_object_unref (folder);
2295 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2300 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2301 TnyList *header_list,
2302 GetMsgAsyncUserCallback user_callback,
2304 GDestroyNotify notify)
2306 ModestMailOperationPrivate *priv = NULL;
2308 TnyIterator *iter = NULL;
2309 gboolean has_uncached_messages;
2311 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2313 /* Init mail operation */
2314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2315 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2317 priv->total = tny_list_get_length(header_list);
2319 /* Check uncached messages */
2320 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2321 !has_uncached_messages && !tny_iterator_is_done (iter);
2322 tny_iterator_next (iter)) {
2325 header = (TnyHeader *) tny_iterator_get_current (iter);
2326 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2327 has_uncached_messages = TRUE;
2328 g_object_unref (header);
2330 g_object_unref (iter);
2331 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2333 /* Get account and set it into mail_operation */
2334 if (tny_list_get_length (header_list) >= 1) {
2335 TnyIterator *iterator = tny_list_create_iterator (header_list);
2336 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2338 TnyFolder *folder = tny_header_get_folder (header);
2340 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2341 g_object_unref (folder);
2343 g_object_unref (header);
2345 g_object_unref (iterator);
2348 msg_list_size = compute_message_list_size (header_list);
2350 modest_mail_operation_notify_start (self);
2351 iter = tny_list_create_iterator (header_list);
2352 if (!tny_iterator_is_done (iter)) {
2353 /* notify about the start of the operation */
2354 ModestMailOperationState *state;
2355 state = modest_mail_operation_clone_state (self);
2358 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2361 GetMsgInfo *msg_info = NULL;
2362 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2363 TnyFolder *folder = tny_header_get_folder (header);
2365 /* Create the message info */
2366 msg_info = g_slice_new0 (GetMsgInfo);
2367 msg_info->mail_op = g_object_ref (self);
2368 msg_info->header = g_object_ref (header);
2369 msg_info->more_msgs = g_object_ref (iter);
2370 msg_info->user_callback = user_callback;
2371 msg_info->user_data = user_data;
2372 msg_info->destroy_notify = notify;
2373 msg_info->last_total_bytes = 0;
2374 msg_info->sum_total_bytes = 0;
2375 msg_info->total_bytes = msg_list_size;
2377 /* The callback will call it per each header */
2378 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2380 /* Free and go on */
2381 g_object_unref (header);
2382 g_object_unref (folder);
2383 g_slice_free (ModestMailOperationState, state);
2385 g_object_unref (iter);
2390 modest_mail_operation_remove_msg (ModestMailOperation *self,
2392 gboolean remove_to_trash /*ignored*/)
2395 ModestMailOperationPrivate *priv;
2397 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2398 g_return_if_fail (TNY_IS_HEADER (header));
2400 if (remove_to_trash)
2401 g_warning ("remove to trash is not implemented");
2403 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2404 folder = tny_header_get_folder (header);
2406 /* Get account and set it into mail_operation */
2407 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2408 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2409 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2411 /* remove message from folder */
2412 tny_folder_remove_msg (folder, header, &(priv->error));
2414 gboolean expunge, leave_on_server;
2415 const gchar *account_name;
2416 TnyAccount *account;
2417 ModestTransportStoreProtocol account_proto;
2419 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2420 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2422 modest_mail_operation_notify_start (self);
2424 /* Get leave on server setting */
2425 account = tny_folder_get_account (folder);
2426 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2428 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2431 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2433 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2434 modest_tny_folder_is_remote_folder (folder) == FALSE)
2440 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2443 g_object_unref (account);
2449 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2451 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2454 g_object_unref (G_OBJECT (folder));
2456 /* Notify about operation end */
2457 modest_mail_operation_notify_end (self);
2461 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2463 gboolean remove_to_trash /*ignored*/)
2465 TnyFolder *folder = NULL;
2466 ModestMailOperationPrivate *priv;
2467 TnyIterator *iter = NULL;
2468 TnyHeader *header = NULL;
2469 TnyList *remove_headers = NULL;
2470 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2472 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2473 g_return_if_fail (TNY_IS_LIST (headers));
2475 if (remove_to_trash)
2476 g_warning ("remove to trash is not implemented");
2478 if (tny_list_get_length(headers) == 0) {
2479 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2480 goto cleanup; /* nothing to do */
2483 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2484 remove_headers = g_object_ref(headers);
2486 /* Get folder from first header and sync it */
2487 iter = tny_list_create_iterator (headers);
2488 header = TNY_HEADER (tny_iterator_get_current (iter));
2490 folder = tny_header_get_folder (header);
2491 if (!TNY_IS_FOLDER(folder)) {
2492 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2496 /* Don't remove messages that are being sent */
2497 if (modest_tny_folder_is_local_folder (folder)) {
2498 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2500 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2501 TnyTransportAccount *traccount = NULL;
2502 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2503 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2505 ModestTnySendQueueStatus status;
2506 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2507 TnyIterator *iter = tny_list_create_iterator(headers);
2508 g_object_unref(remove_headers);
2509 remove_headers = TNY_LIST(tny_simple_list_new());
2510 while (!tny_iterator_is_done(iter)) {
2512 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2513 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2514 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2515 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2516 tny_list_append(remove_headers, G_OBJECT(hdr));
2518 g_object_unref(hdr);
2520 tny_iterator_next(iter);
2522 g_object_unref(iter);
2523 g_object_unref(traccount);
2527 /* Get account and set it into mail_operation */
2528 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2529 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2530 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2532 /* remove message from folder */
2533 modest_mail_operation_notify_start (self);
2535 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2537 gboolean expunge, leave_on_server;
2538 const gchar *account_name;
2540 TnyAccount *account;
2541 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2543 account = tny_folder_get_account (folder);
2544 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2546 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2549 proto = tny_account_get_proto (account);
2551 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2554 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2555 modest_tny_folder_is_remote_folder (folder) == FALSE)
2561 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2563 g_object_unref (account);
2569 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2571 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2576 g_object_unref (remove_headers);
2578 g_object_unref (header);
2580 g_object_unref (iter);
2582 g_object_unref (folder);
2584 /* Notify about operation end */
2585 modest_mail_operation_notify_end (self);
2589 notify_progress_of_multiple_messages (ModestMailOperation *self,
2591 gint *last_total_bytes,
2592 gint *sum_total_bytes,
2594 gboolean increment_done)
2596 ModestMailOperationPrivate *priv;
2597 ModestMailOperationState *state;
2598 gboolean is_num_bytes = FALSE;
2600 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2602 /* We know that tinymail sends us information about
2603 * transferred bytes with this particular message
2605 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2606 * I just added the 'if' so we don't get runtime warning)
2608 if (status->message)
2609 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2611 state = modest_mail_operation_clone_state (self);
2612 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2613 /* We know that we're in a different message when the
2614 total number of bytes to transfer is different. Of
2615 course it could fail if we're transferring messages
2616 of the same size, but this is a workarround */
2617 if (status->of_total != *last_total_bytes) {
2618 /* We need to increment the done when there is
2619 no information about each individual
2620 message, we need to do this in message
2621 transfers, and we don't do it for getting
2625 *sum_total_bytes += *last_total_bytes;
2626 *last_total_bytes = status->of_total;
2628 state->bytes_done += status->position + *sum_total_bytes;
2629 state->bytes_total = total_bytes;
2631 /* Notify the status change. Only notify about changes
2632 referred to bytes */
2633 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2637 g_slice_free (ModestMailOperationState, state);
2641 transfer_msgs_status_cb (GObject *obj,
2645 XFerMsgsAsyncHelper *helper;
2647 g_return_if_fail (status != NULL);
2649 /* Show only the status information we want */
2650 if (status->code != TNY_FOLDER_STATUS_CODE_XFER_MSGS)
2653 helper = (XFerMsgsAsyncHelper *) user_data;
2654 g_return_if_fail (helper != NULL);
2656 /* Notify progress */
2657 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2658 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2663 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2665 XFerMsgsAsyncHelper *helper;
2666 ModestMailOperation *self;
2667 ModestMailOperationPrivate *priv;
2668 gboolean finished = TRUE;
2670 helper = (XFerMsgsAsyncHelper *) user_data;
2671 self = helper->mail_op;
2673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2676 priv->error = g_error_copy (err);
2678 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2679 } else if (cancelled) {
2680 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2681 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2682 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2683 _("Error trying to refresh the contents of %s"),
2684 tny_folder_get_name (folder));
2685 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2686 if (helper->more_msgs) {
2687 /* We'll transfer the next message in the list */
2688 tny_iterator_next (helper->more_msgs);
2689 if (!tny_iterator_is_done (helper->more_msgs)) {
2690 GObject *next_header;
2691 g_object_unref (helper->headers);
2692 helper->headers = tny_simple_list_new ();
2693 next_header = tny_iterator_get_current (helper->more_msgs);
2694 tny_list_append (helper->headers, next_header);
2695 g_object_unref (next_header);
2702 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2708 /* Update folder counts */
2709 tny_folder_poke_status (folder);
2710 tny_folder_poke_status (helper->dest_folder);
2712 /* Notify about operation end */
2713 modest_mail_operation_notify_end (self);
2715 /* If user defined callback function was defined, call it */
2716 if (helper->user_callback) {
2717 /* This is not a GDK lock because we are a Tinymail callback and
2718 * Tinymail already acquires the Gdk lock */
2720 /* no gdk_threads_enter (), CHECKED */
2721 helper->user_callback (self, helper->user_data);
2722 /* no gdk_threads_leave (), CHECKED */
2726 if (helper->more_msgs)
2727 g_object_unref (helper->more_msgs);
2728 if (helper->headers)
2729 g_object_unref (helper->headers);
2730 if (helper->dest_folder)
2731 g_object_unref (helper->dest_folder);
2732 if (helper->mail_op)
2733 g_object_unref (helper->mail_op);
2734 g_slice_free (XFerMsgsAsyncHelper, helper);
2736 /* Transfer more messages */
2737 tny_folder_transfer_msgs_async (folder,
2739 helper->dest_folder,
2742 transfer_msgs_status_cb,
2748 compute_message_list_size (TnyList *headers)
2753 iter = tny_list_create_iterator (headers);
2754 while (!tny_iterator_is_done (iter)) {
2755 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2756 size += tny_header_get_message_size (header);
2757 g_object_unref (header);
2758 tny_iterator_next (iter);
2760 g_object_unref (iter);
2766 compute_message_array_size (GPtrArray *headers)
2771 for (i = 0; i < headers->len; i++) {
2772 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2773 size += tny_header_get_message_size (header);
2781 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2784 gboolean delete_original,
2785 XferMsgsAsyncUserCallback user_callback,
2788 ModestMailOperationPrivate *priv = NULL;
2789 TnyIterator *iter = NULL;
2790 TnyFolder *src_folder = NULL;
2791 XFerMsgsAsyncHelper *helper = NULL;
2792 TnyHeader *header = NULL;
2793 ModestTnyFolderRules rules = 0;
2794 TnyAccount *dst_account = NULL;
2795 gboolean leave_on_server;
2797 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2798 g_return_if_fail (headers && TNY_IS_LIST (headers));
2799 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2801 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2802 priv->total = tny_list_get_length (headers);
2804 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2805 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2807 /* Apply folder rules */
2808 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2809 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2810 /* Set status failed and set an error */
2811 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2812 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2813 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2814 _CS("ckct_ib_unable_to_paste_here"));
2815 /* Notify the queue */
2816 modest_mail_operation_notify_end (self);
2820 /* Get source folder */
2821 iter = tny_list_create_iterator (headers);
2822 header = TNY_HEADER (tny_iterator_get_current (iter));
2824 src_folder = tny_header_get_folder (header);
2825 g_object_unref (header);
2827 g_object_unref (iter);
2829 if (src_folder == NULL) {
2830 /* Notify the queue */
2831 modest_mail_operation_notify_end (self);
2833 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2838 /* Check folder source and destination */
2839 if (src_folder == folder) {
2840 /* Set status failed and set an error */
2841 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2842 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2843 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2844 _("mail_in_ui_folder_copy_target_error"));
2846 /* Notify the queue */
2847 modest_mail_operation_notify_end (self);
2850 g_object_unref (src_folder);
2854 /* Create the helper */
2855 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2856 helper->mail_op = g_object_ref(self);
2857 helper->dest_folder = g_object_ref(folder);
2858 helper->user_callback = user_callback;
2859 helper->user_data = user_data;
2860 helper->delete = delete_original;
2861 helper->last_total_bytes = 0;
2862 helper->sum_total_bytes = 0;
2863 helper->total_bytes = compute_message_list_size (headers);
2865 /* Get account and set it into mail_operation */
2866 priv->account = modest_tny_folder_get_account (src_folder);
2867 dst_account = modest_tny_folder_get_account (folder);
2869 if (priv->account == dst_account) {
2870 /* Transfer all messages at once using the fast
2871 * method. Note that depending on the server this
2872 * might not be that fast, and might not be
2873 * user-cancellable either */
2874 helper->headers = g_object_ref (headers);
2875 helper->more_msgs = NULL;
2877 /* Transfer messages one by one so the user can cancel
2880 helper->headers = tny_simple_list_new ();
2881 helper->more_msgs = tny_list_create_iterator (headers);
2882 hdr = tny_iterator_get_current (helper->more_msgs);
2883 tny_list_append (helper->headers, hdr);
2884 g_object_unref (hdr);
2887 /* If leave_on_server is set to TRUE then don't use
2888 delete_original, we always pass FALSE. This is because
2889 otherwise tinymail will try to sync the source folder and
2890 this could cause an error if we're offline while
2891 transferring an already downloaded message from a POP
2893 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2894 MODEST_PROTOCOL_STORE_POP) {
2895 const gchar *account_name;
2897 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2898 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2901 leave_on_server = FALSE;
2904 modest_mail_operation_notify_start (self);
2905 tny_folder_transfer_msgs_async (src_folder,
2908 (leave_on_server) ? FALSE : delete_original,
2910 transfer_msgs_status_cb,
2912 g_object_unref (src_folder);
2913 g_object_unref (dst_account);
2918 on_refresh_folder (TnyFolder *folder,
2923 RefreshAsyncHelper *helper = NULL;
2924 ModestMailOperation *self = NULL;
2925 ModestMailOperationPrivate *priv = NULL;
2927 helper = (RefreshAsyncHelper *) user_data;
2928 self = helper->mail_op;
2929 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2931 g_return_if_fail(priv!=NULL);
2934 priv->error = g_error_copy (error);
2935 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2940 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2942 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2943 _("Error trying to refresh the contents of %s"),
2944 tny_folder_get_name (folder));
2948 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2951 /* Call user defined callback, if it exists */
2952 if (helper->user_callback) {
2954 /* This is not a GDK lock because we are a Tinymail callback and
2955 * Tinymail already acquires the Gdk lock */
2956 helper->user_callback (self, folder, helper->user_data);
2960 g_slice_free (RefreshAsyncHelper, helper);
2962 /* Notify about operation end */
2963 modest_mail_operation_notify_end (self);
2964 g_object_unref(self);
2968 on_refresh_folder_status_update (GObject *obj,
2972 RefreshAsyncHelper *helper = NULL;
2973 ModestMailOperation *self = NULL;
2974 ModestMailOperationPrivate *priv = NULL;
2975 ModestMailOperationState *state;
2977 g_return_if_fail (user_data != NULL);
2978 g_return_if_fail (status != NULL);
2980 /* Show only the status information we want */
2981 if (status->code != TNY_FOLDER_STATUS_CODE_REFRESH)
2984 helper = (RefreshAsyncHelper *) user_data;
2985 self = helper->mail_op;
2986 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2988 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2990 priv->done = status->position;
2991 priv->total = status->of_total;
2993 state = modest_mail_operation_clone_state (self);
2995 /* This is not a GDK lock because we are a Tinymail callback and
2996 * Tinymail already acquires the Gdk lock */
2997 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2999 g_slice_free (ModestMailOperationState, state);
3003 modest_mail_operation_refresh_folder (ModestMailOperation *self,
3005 RefreshAsyncUserCallback user_callback,
3008 ModestMailOperationPrivate *priv = NULL;
3009 RefreshAsyncHelper *helper = NULL;
3011 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3013 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3015 /* Get account and set it into mail_operation */
3016 priv->account = modest_tny_folder_get_account (folder);
3017 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
3019 /* Create the helper */
3020 helper = g_slice_new0 (RefreshAsyncHelper);
3021 helper->mail_op = g_object_ref(self);
3022 helper->user_callback = user_callback;
3023 helper->user_data = user_data;
3025 modest_mail_operation_notify_start (self);
3027 /* notify that the operation was started */
3028 ModestMailOperationState *state;
3029 state = modest_mail_operation_clone_state (self);
3032 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
3035 /* FIXME: we're leaking the state here, or? valgrind thinks so */
3037 tny_folder_refresh_async (folder,
3039 on_refresh_folder_status_update,
3044 run_queue_stop (ModestTnySendQueue *queue,
3045 ModestMailOperation *self)
3047 ModestMailOperationPrivate *priv;
3049 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3050 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3051 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3053 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3055 modest_mail_operation_notify_end (self);
3056 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
3057 g_object_unref (self);
3060 modest_mail_operation_run_queue (ModestMailOperation *self,
3061 ModestTnySendQueue *queue)
3063 ModestMailOperationPrivate *priv;
3065 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3066 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
3067 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3069 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3070 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3071 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3073 modest_mail_operation_notify_start (self);
3074 g_object_ref (self);
3075 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3079 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3081 ModestMailOperationPrivate *priv;
3083 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3085 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3086 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3088 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3090 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3092 modest_mail_operation_notify_end (mail_op);
3093 g_object_unref (mail_op);
3097 modest_mail_operation_sync_folder (ModestMailOperation *self,
3098 TnyFolder *folder, gboolean expunge)
3100 ModestMailOperationPrivate *priv;
3102 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3103 g_return_if_fail (TNY_IS_FOLDER (folder));
3104 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3106 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3107 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3108 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3110 modest_mail_operation_notify_start (self);
3111 g_object_ref (self);
3112 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3116 modest_mail_operation_notify_start (ModestMailOperation *self)
3118 ModestMailOperationPrivate *priv = NULL;
3120 g_return_if_fail (self);
3122 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3124 /* Ensure that all the fields are filled correctly */
3125 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3127 /* Notify the observers about the mail operation. We do not
3128 wrapp this emission because we assume that this function is
3129 always called from within the main lock */
3130 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3135 * It's used by the mail operation queue to notify the observers
3136 * attached to that signal that the operation finished. We need to use
3137 * that because tinymail does not give us the progress of a given
3138 * operation when it finishes (it directly calls the operation
3142 modest_mail_operation_notify_end (ModestMailOperation *self)
3144 ModestMailOperationPrivate *priv = NULL;
3146 g_return_if_fail (self);
3148 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3150 /* Notify the observers about the mail operation end. We do
3151 not wrapp this emission because we assume that this
3152 function is always called from within the main lock */
3153 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3155 /* Remove the error user data */
3156 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3157 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3161 modest_mail_operation_get_account (ModestMailOperation *self)
3163 ModestMailOperationPrivate *priv = NULL;
3165 g_return_val_if_fail (self, NULL);
3167 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3169 return (priv->account) ? g_object_ref (priv->account) : NULL;
3173 modest_mail_operation_noop (ModestMailOperation *self)
3175 ModestMailOperationPrivate *priv = NULL;
3177 g_return_if_fail (self);
3179 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3180 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3181 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3185 /* This mail operation does nothing actually */
3186 modest_mail_operation_notify_start (self);
3187 modest_mail_operation_notify_end (self);
3192 modest_mail_operation_to_string (ModestMailOperation *self)
3194 const gchar *type, *status, *account_id;
3195 ModestMailOperationPrivate *priv = NULL;
3197 g_return_val_if_fail (self, NULL);
3199 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3201 /* new operations don't have anything interesting */
3202 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3203 return g_strdup_printf ("%p <new operation>", self);
3205 switch (priv->op_type) {
3206 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3207 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3208 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3209 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3210 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3211 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3212 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3213 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3214 default: type = "UNEXPECTED"; break;
3217 switch (priv->status) {
3218 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3219 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3220 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3221 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3222 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3223 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3224 default: status= "UNEXPECTED"; break;
3227 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3229 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3230 priv->done, priv->total,
3231 priv->error && priv->error->message ? priv->error->message : "");