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"
67 * Remove all these #ifdef stuff when the tinymail's idle calls become
70 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
72 /* 'private'/'protected' functions */
73 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
74 static void modest_mail_operation_init (ModestMailOperation *obj);
75 static void modest_mail_operation_finalize (GObject *obj);
77 static void get_msg_async_cb (TnyFolder *folder,
83 static void get_msg_status_cb (GObject *obj,
87 static void modest_mail_operation_notify_start (ModestMailOperation *self);
88 static void modest_mail_operation_notify_end (ModestMailOperation *self);
90 static void notify_progress_of_multiple_messages (ModestMailOperation *self,
92 gint *last_total_bytes,
93 gint *sum_total_bytes,
95 gboolean increment_done);
97 static guint compute_message_list_size (TnyList *headers);
99 static guint compute_message_array_size (GPtrArray *headers);
101 static int compare_headers_by_date (gconstpointer a,
104 enum _ModestMailOperationSignals
106 PROGRESS_CHANGED_SIGNAL,
107 OPERATION_STARTED_SIGNAL,
108 OPERATION_FINISHED_SIGNAL,
112 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
113 struct _ModestMailOperationPrivate {
119 ErrorCheckingUserCallback error_checking;
120 gpointer error_checking_user_data;
121 ErrorCheckingUserDataDestroyer error_checking_user_data_destroyer;
122 ModestMailOperationStatus status;
123 ModestMailOperationTypeOperation op_type;
126 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
127 MODEST_TYPE_MAIL_OPERATION, \
128 ModestMailOperationPrivate))
130 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
131 priv->status = new_status;\
136 GetMsgAsyncUserCallback user_callback;
138 TnyIterator *more_msgs;
140 ModestMailOperation *mail_op;
141 GDestroyNotify destroy_notify;
142 gint last_total_bytes;
143 gint sum_total_bytes;
147 typedef struct _RefreshAsyncHelper {
148 ModestMailOperation *mail_op;
149 RefreshAsyncUserCallback user_callback;
151 } RefreshAsyncHelper;
153 typedef struct _XFerMsgsAsyncHelper
155 ModestMailOperation *mail_op;
157 TnyIterator *more_msgs;
158 TnyFolder *dest_folder;
159 XferMsgsAsyncUserCallback user_callback;
162 gint last_total_bytes;
163 gint sum_total_bytes;
165 } XFerMsgsAsyncHelper;
167 typedef struct _XFerFolderAsyncHelper
169 ModestMailOperation *mail_op;
170 XferFolderAsyncUserCallback user_callback;
172 } XFerFolderAsyncHelper;
174 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
178 static void modest_mail_operation_create_msg (ModestMailOperation *self,
179 const gchar *from, const gchar *to,
180 const gchar *cc, const gchar *bcc,
181 const gchar *subject, const gchar *plain_body,
182 const gchar *html_body, const GList *attachments_list,
183 const GList *images_list,
184 TnyHeaderFlags priority_flags,
185 ModestMailOperationCreateMsgCallback callback,
188 static gboolean idle_notify_queue (gpointer data);
191 ModestMailOperation *mail_op;
199 GList *attachments_list;
201 TnyHeaderFlags priority_flags;
202 ModestMailOperationCreateMsgCallback callback;
208 ModestMailOperation *mail_op;
210 ModestMailOperationCreateMsgCallback callback;
215 static GObjectClass *parent_class = NULL;
217 static guint signals[NUM_SIGNALS] = {0};
220 modest_mail_operation_get_type (void)
222 static GType my_type = 0;
224 static const GTypeInfo my_info = {
225 sizeof(ModestMailOperationClass),
226 NULL, /* base init */
227 NULL, /* base finalize */
228 (GClassInitFunc) modest_mail_operation_class_init,
229 NULL, /* class finalize */
230 NULL, /* class data */
231 sizeof(ModestMailOperation),
233 (GInstanceInitFunc) modest_mail_operation_init,
236 my_type = g_type_register_static (G_TYPE_OBJECT,
237 "ModestMailOperation",
244 modest_mail_operation_class_init (ModestMailOperationClass *klass)
246 GObjectClass *gobject_class;
247 gobject_class = (GObjectClass*) klass;
249 parent_class = g_type_class_peek_parent (klass);
250 gobject_class->finalize = modest_mail_operation_finalize;
252 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
255 * ModestMailOperation::progress-changed
256 * @self: the #MailOperation that emits the signal
257 * @user_data: user data set when the signal handler was connected
259 * Emitted when the progress of a mail operation changes
261 signals[PROGRESS_CHANGED_SIGNAL] =
262 g_signal_new ("progress-changed",
263 G_TYPE_FROM_CLASS (gobject_class),
265 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
267 g_cclosure_marshal_VOID__POINTER,
268 G_TYPE_NONE, 1, G_TYPE_POINTER);
272 * This signal is issued whenever a mail operation starts, and
273 * starts mean when the tinymail operation is issued. This
274 * means that it could happen that something wrong happens and
275 * the tinymail function is never called. In this situation a
276 * operation-finished will be issued without any
279 signals[OPERATION_STARTED_SIGNAL] =
280 g_signal_new ("operation-started",
281 G_TYPE_FROM_CLASS (gobject_class),
283 G_STRUCT_OFFSET (ModestMailOperationClass, operation_started),
285 g_cclosure_marshal_VOID__VOID,
290 * This signal is issued whenever a mail operation
291 * finishes. Note that this signal could be issued without any
292 * previous "operation-started" signal, because this last one
293 * is only issued when the tinymail operation is successfully
296 signals[OPERATION_FINISHED_SIGNAL] =
297 g_signal_new ("operation-finished",
298 G_TYPE_FROM_CLASS (gobject_class),
300 G_STRUCT_OFFSET (ModestMailOperationClass, operation_finished),
302 g_cclosure_marshal_VOID__VOID,
307 modest_mail_operation_init (ModestMailOperation *obj)
309 ModestMailOperationPrivate *priv;
311 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
313 priv->account = NULL;
314 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
315 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
320 priv->error_checking = NULL;
321 priv->error_checking_user_data = NULL;
325 modest_mail_operation_finalize (GObject *obj)
327 ModestMailOperationPrivate *priv;
329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
334 g_error_free (priv->error);
338 g_object_unref (priv->source);
342 g_object_unref (priv->account);
343 priv->account = NULL;
347 G_OBJECT_CLASS(parent_class)->finalize (obj);
351 modest_mail_operation_new (GObject *source)
353 ModestMailOperation *obj;
354 ModestMailOperationPrivate *priv;
356 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
357 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
360 priv->source = g_object_ref(source);
366 modest_mail_operation_new_with_error_handling (GObject *source,
367 ErrorCheckingUserCallback error_handler,
369 ErrorCheckingUserDataDestroyer error_handler_destroyer)
371 ModestMailOperation *obj;
372 ModestMailOperationPrivate *priv;
374 obj = modest_mail_operation_new (source);
375 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
377 g_return_val_if_fail (error_handler != NULL, obj);
378 priv->error_checking = error_handler;
379 priv->error_checking_user_data = user_data;
380 priv->error_checking_user_data_destroyer = error_handler_destroyer;
386 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
388 ModestMailOperationPrivate *priv;
390 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION(self));
392 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
393 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
395 /* Call the user callback */
396 if (priv->error_checking != NULL)
397 priv->error_checking (self, priv->error_checking_user_data);
401 ModestMailOperationTypeOperation
402 modest_mail_operation_get_type_operation (ModestMailOperation *self)
404 ModestMailOperationPrivate *priv;
406 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
407 MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
411 return priv->op_type;
415 modest_mail_operation_is_mine (ModestMailOperation *self,
418 ModestMailOperationPrivate *priv;
420 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
424 if (priv->source == NULL) return FALSE;
426 return priv->source == me;
430 modest_mail_operation_get_source (ModestMailOperation *self)
432 ModestMailOperationPrivate *priv;
434 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
437 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
439 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
443 return (priv->source) ? g_object_ref (priv->source) : NULL;
446 ModestMailOperationStatus
447 modest_mail_operation_get_status (ModestMailOperation *self)
449 ModestMailOperationPrivate *priv;
451 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
452 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
453 MODEST_MAIL_OPERATION_STATUS_INVALID);
455 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
457 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
458 return MODEST_MAIL_OPERATION_STATUS_INVALID;
465 modest_mail_operation_get_error (ModestMailOperation *self)
467 ModestMailOperationPrivate *priv;
469 g_return_val_if_fail (self, NULL);
470 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
472 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
475 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
483 modest_mail_operation_cancel (ModestMailOperation *self)
485 ModestMailOperationPrivate *priv;
486 gboolean canceled = FALSE;
488 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION (self), FALSE);
490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
493 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
495 /* Cancel the mail operation */
496 g_return_val_if_fail (priv->account, FALSE);
497 tny_account_cancel (priv->account);
499 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_SEND) {
500 ModestTnySendQueue *queue;
501 queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (priv->account));
503 /* Cancel the sending of the following next messages */
504 tny_send_queue_cancel (TNY_SEND_QUEUE (queue), TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, NULL);
511 modest_mail_operation_get_task_done (ModestMailOperation *self)
513 ModestMailOperationPrivate *priv;
515 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
518 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
523 modest_mail_operation_get_task_total (ModestMailOperation *self)
525 ModestMailOperationPrivate *priv;
527 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
530 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
535 modest_mail_operation_is_finished (ModestMailOperation *self)
537 ModestMailOperationPrivate *priv;
538 gboolean retval = FALSE;
540 g_return_val_if_fail (self && MODEST_IS_MAIL_OPERATION(self),
543 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
545 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
546 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
547 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
548 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
558 * Creates an image of the current state of a mail operation, the
559 * caller must free it
561 static ModestMailOperationState *
562 modest_mail_operation_clone_state (ModestMailOperation *self)
564 ModestMailOperationState *state;
565 ModestMailOperationPrivate *priv;
567 /* FIXME: this should be fixed properly
569 * in some cases, priv was NULL, so checking here to
572 g_return_val_if_fail (self, NULL);
573 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
574 g_return_val_if_fail (priv, NULL);
579 state = g_slice_new (ModestMailOperationState);
581 state->status = priv->status;
582 state->op_type = priv->op_type;
583 state->done = priv->done;
584 state->total = priv->total;
585 state->finished = modest_mail_operation_is_finished (self);
586 state->bytes_done = 0;
587 state->bytes_total = 0;
592 /* ******************************************************************* */
593 /* ************************** SEND ACTIONS ************************* */
594 /* ******************************************************************* */
597 modest_mail_operation_send_mail (ModestMailOperation *self,
598 TnyTransportAccount *transport_account,
601 TnySendQueue *send_queue = NULL;
602 ModestMailOperationPrivate *priv;
604 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
605 g_return_if_fail (transport_account && TNY_IS_TRANSPORT_ACCOUNT (transport_account));
606 g_return_if_fail (msg && TNY_IS_MSG (msg));
608 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
610 /* Get account and set it into mail_operation */
611 priv->account = g_object_ref (transport_account);
612 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
616 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
617 if (!TNY_IS_SEND_QUEUE(send_queue)) {
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
620 "modest: could not find send queue for account\n");
621 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
622 modest_mail_operation_notify_end (self);
625 /* Add the msg to the queue */
626 modest_mail_operation_notify_start (self);
628 tny_send_queue_add_async (send_queue, msg, NULL, NULL, NULL);
630 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
631 modest_mail_operation_notify_end (self);
638 idle_create_msg_cb (gpointer idle_data)
640 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
642 /* This is a GDK lock because we are an idle callback and
643 * info->callback can contain Gtk+ code */
645 gdk_threads_enter (); /* CHECKED */
646 info->callback (info->mail_op, info->msg, info->userdata);
648 g_object_unref (info->mail_op);
650 g_object_unref (info->msg);
651 g_slice_free (CreateMsgIdleInfo, info);
652 gdk_threads_leave (); /* CHECKED */
658 create_msg_thread (gpointer thread_data)
660 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
661 TnyMsg *new_msg = NULL;
662 ModestMailOperationPrivate *priv;
664 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
665 if (info->html_body == NULL) {
666 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
667 info->bcc, info->subject, info->plain_body,
668 info->attachments_list);
670 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
671 info->bcc, info->subject, info->html_body,
672 info->plain_body, info->attachments_list,
679 /* Set priority flags in message */
680 header = tny_msg_get_header (new_msg);
681 tny_header_set_flag (header, info->priority_flags);
683 /* Set attachment flags in message */
684 if (info->attachments_list != NULL)
685 tny_header_set_flag (header, TNY_HEADER_FLAG_ATTACHMENTS);
687 g_object_unref (G_OBJECT(header));
689 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
690 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
691 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
692 "modest: failed to create a new msg\n");
700 g_free (info->plain_body);
701 g_free (info->html_body);
702 g_free (info->subject);
703 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
704 g_list_free (info->attachments_list);
705 g_list_foreach (info->images_list, (GFunc) g_object_unref, NULL);
706 g_list_free (info->images_list);
708 if (info->callback) {
709 CreateMsgIdleInfo *idle_info;
710 idle_info = g_slice_new0 (CreateMsgIdleInfo);
711 idle_info->mail_op = g_object_ref (info->mail_op);
712 idle_info->msg = (new_msg) ? g_object_ref (new_msg) : NULL;
713 idle_info->callback = info->callback;
714 idle_info->userdata = info->userdata;
715 g_idle_add (idle_create_msg_cb, idle_info);
717 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
720 g_object_unref (info->mail_op);
721 g_slice_free (CreateMsgInfo, info);
722 if (new_msg) g_object_unref(new_msg);
728 modest_mail_operation_create_msg (ModestMailOperation *self,
729 const gchar *from, const gchar *to,
730 const gchar *cc, const gchar *bcc,
731 const gchar *subject, const gchar *plain_body,
732 const gchar *html_body,
733 const GList *attachments_list,
734 const GList *images_list,
735 TnyHeaderFlags priority_flags,
736 ModestMailOperationCreateMsgCallback callback,
739 CreateMsgInfo *info = NULL;
741 info = g_slice_new0 (CreateMsgInfo);
742 info->mail_op = g_object_ref (self);
744 info->from = g_strdup (from);
745 info->to = g_strdup (to);
746 info->cc = g_strdup (cc);
747 info->bcc = g_strdup (bcc);
748 info->subject = g_strdup (subject);
749 info->plain_body = g_strdup (plain_body);
750 info->html_body = g_strdup (html_body);
751 info->attachments_list = g_list_copy ((GList *) attachments_list);
752 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
753 info->images_list = g_list_copy ((GList *) images_list);
754 g_list_foreach (info->images_list, (GFunc) g_object_ref, NULL);
755 info->priority_flags = priority_flags;
757 info->callback = callback;
758 info->userdata = userdata;
760 g_thread_create (create_msg_thread, info, FALSE, NULL);
765 TnyTransportAccount *transport_account;
770 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
774 ModestMailOperationPrivate *priv = NULL;
775 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
776 TnyFolder *draft_folder = NULL;
777 TnyFolder *outbox_folder = NULL;
778 TnyHeader *header = NULL;
785 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
788 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
789 modest_mail_operation_notify_end (self);
793 /* Call mail operation */
794 modest_mail_operation_send_mail (self, info->transport_account, msg);
796 if (info->draft_msg != NULL) {
797 TnyFolder *folder = NULL;
798 TnyFolder *src_folder = NULL;
799 TnyFolderType folder_type;
800 TnyTransportAccount *transport_account = NULL;
802 /* To remove the old mail from its source folder, we need to get the
803 * transport account of the original draft message (the transport account
804 * might have been changed by the user) */
805 header = tny_msg_get_header (info->draft_msg);
806 transport_account = modest_tny_account_store_get_transport_account_from_outbox_header(
807 modest_runtime_get_account_store(), header);
808 if (transport_account == NULL)
809 transport_account = g_object_ref(info->transport_account);
810 draft_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
811 TNY_FOLDER_TYPE_DRAFTS);
812 outbox_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account),
813 TNY_FOLDER_TYPE_OUTBOX);
814 g_object_unref(transport_account);
817 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL drafts folder",
821 if (!outbox_folder) {
822 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL outbox folder",
827 folder = tny_msg_get_folder (info->draft_msg);
828 if (folder == NULL) goto end;
829 folder_type = modest_tny_folder_guess_folder_type (folder);
831 if (folder_type == TNY_FOLDER_TYPE_INVALID)
832 g_warning ("%s: BUG: folder of type TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
834 if (folder_type == TNY_FOLDER_TYPE_OUTBOX)
835 src_folder = outbox_folder;
837 src_folder = draft_folder;
839 /* Note: This can fail (with a warning) if the message is not really already in a folder,
840 * because this function requires it to have a UID. */
841 tny_folder_remove_msg (src_folder, header, NULL);
843 tny_folder_sync (folder, TRUE, &err); /* FALSE --> don't expunge */
844 /* tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL); /\* expunge *\/ */
846 g_object_unref (folder);
851 g_object_unref (header);
855 g_object_unref (info->draft_msg);
857 g_object_unref (draft_folder);
859 g_object_unref (outbox_folder);
860 if (info->transport_account)
861 g_object_unref (info->transport_account);
862 g_slice_free (SendNewMailInfo, info);
866 modest_mail_operation_send_new_mail (ModestMailOperation *self,
867 TnyTransportAccount *transport_account,
869 const gchar *from, const gchar *to,
870 const gchar *cc, const gchar *bcc,
871 const gchar *subject, const gchar *plain_body,
872 const gchar *html_body,
873 const GList *attachments_list,
874 const GList *images_list,
875 TnyHeaderFlags priority_flags)
877 ModestMailOperationPrivate *priv = NULL;
878 SendNewMailInfo *info;
880 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
881 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
883 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
884 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND;
885 priv->account = TNY_ACCOUNT (g_object_ref (transport_account));
886 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
888 /* Check parametters */
890 /* Set status failed and set an error */
891 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
892 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
893 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
894 _("Error trying to send a mail. You need to set at least one recipient"));
897 info = g_slice_new0 (SendNewMailInfo);
898 info->transport_account = transport_account;
899 if (transport_account)
900 g_object_ref (transport_account);
901 info->draft_msg = draft_msg;
903 g_object_ref (draft_msg);
906 modest_mail_operation_notify_start (self);
907 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
908 attachments_list, images_list, priority_flags,
909 modest_mail_operation_send_new_mail_cb, info);
915 TnyTransportAccount *transport_account;
917 SaveToDraftstCallback callback;
921 ModestMailOperation *mailop;
922 } SaveToDraftsAddMsgInfo;
925 modest_mail_operation_save_to_drafts_add_msg_cb(TnyFolder *self,
930 ModestMailOperationPrivate *priv = NULL;
931 SaveToDraftsAddMsgInfo *info = (SaveToDraftsAddMsgInfo *) userdata;
933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mailop);
936 g_warning ("%s: priv->error != NULL", __FUNCTION__);
937 g_error_free(priv->error);
940 priv->error = (err == NULL) ? NULL : g_error_copy(err);
942 if ((!priv->error) && (info->draft_msg != NULL)) {
943 TnyHeader *header = tny_msg_get_header (info->draft_msg);
944 TnyFolder *src_folder = tny_header_get_folder (header);
946 /* Remove the old draft */
947 tny_folder_remove_msg (src_folder, header, NULL);
949 /* Synchronize to expunge and to update the msg counts */
950 tny_folder_sync_async (info->drafts, TRUE, NULL, NULL, NULL);
951 tny_folder_sync_async (src_folder, TRUE, NULL, NULL, NULL);
953 g_object_unref (G_OBJECT(header));
954 g_object_unref (G_OBJECT(src_folder));
958 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
960 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
962 /* Call the user callback */
964 info->callback (info->mailop, info->msg, info->user_data);
966 if (info->transport_account)
967 g_object_unref (G_OBJECT(info->transport_account));
969 g_object_unref (G_OBJECT (info->draft_msg));
971 g_object_unref (G_OBJECT(info->drafts));
973 g_object_unref (G_OBJECT (info->msg));
975 modest_mail_operation_notify_end (info->mailop);
976 g_object_unref(info->mailop);
977 g_slice_free (SaveToDraftsAddMsgInfo, info);
982 TnyTransportAccount *transport_account;
984 SaveToDraftstCallback callback;
989 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
993 TnyFolder *drafts = NULL;
994 ModestMailOperationPrivate *priv = NULL;
995 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
997 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1000 if (!(priv->error)) {
1001 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1002 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1003 "modest: failed to create a new msg\n");
1006 drafts = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account),
1007 TNY_FOLDER_TYPE_DRAFTS);
1008 if (!drafts && !(priv->error)) {
1009 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1010 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1011 "modest: failed to create a new msg\n");
1016 SaveToDraftsAddMsgInfo *cb_info = g_slice_new(SaveToDraftsAddMsgInfo);
1017 cb_info->transport_account = g_object_ref(info->transport_account);
1018 cb_info->draft_msg = info->draft_msg ? g_object_ref(info->draft_msg) : NULL;
1019 cb_info->callback = info->callback;
1020 cb_info->user_data = info->user_data;
1021 cb_info->drafts = g_object_ref(drafts);
1022 cb_info->msg = g_object_ref(msg);
1023 cb_info->mailop = g_object_ref(self);
1024 tny_folder_add_msg_async(drafts, msg, modest_mail_operation_save_to_drafts_add_msg_cb,
1027 /* Call the user callback */
1028 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1030 info->callback (self, msg, info->user_data);
1031 modest_mail_operation_notify_end (self);
1035 g_object_unref (G_OBJECT(drafts));
1036 if (info->draft_msg)
1037 g_object_unref (G_OBJECT (info->draft_msg));
1038 if (info->transport_account)
1039 g_object_unref (G_OBJECT(info->transport_account));
1040 g_slice_free (SaveToDraftsInfo, info);
1044 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
1045 TnyTransportAccount *transport_account,
1047 const gchar *from, const gchar *to,
1048 const gchar *cc, const gchar *bcc,
1049 const gchar *subject, const gchar *plain_body,
1050 const gchar *html_body,
1051 const GList *attachments_list,
1052 const GList *images_list,
1053 TnyHeaderFlags priority_flags,
1054 SaveToDraftstCallback callback,
1057 ModestMailOperationPrivate *priv = NULL;
1058 SaveToDraftsInfo *info = NULL;
1060 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1061 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
1063 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1065 /* Get account and set it into mail_operation */
1066 priv->account = g_object_ref (transport_account);
1067 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1069 info = g_slice_new0 (SaveToDraftsInfo);
1070 info->transport_account = g_object_ref (transport_account);
1071 info->draft_msg = (draft_msg) ? g_object_ref (draft_msg) : NULL;
1072 info->callback = callback;
1073 info->user_data = user_data;
1075 modest_mail_operation_notify_start (self);
1076 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
1077 attachments_list, images_list, priority_flags,
1078 modest_mail_operation_save_to_drafts_cb, info);
1083 ModestMailOperation *mail_op;
1084 TnyMimePart *mime_part;
1086 GetMimePartSizeCallback callback;
1088 } GetMimePartSizeInfo;
1090 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
1091 /* We use this folder observer to track the headers that have been
1092 * added to a folder */
1095 TnyList *new_headers;
1096 } InternalFolderObserver;
1099 GObjectClass parent;
1100 } InternalFolderObserverClass;
1102 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
1104 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
1105 internal_folder_observer,
1107 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
1111 foreach_add_item (gpointer header, gpointer user_data)
1113 tny_list_prepend (TNY_LIST (user_data),
1114 g_object_ref (G_OBJECT (header)));
1117 /* This is the method that looks for new messages in a folder */
1119 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
1121 InternalFolderObserver *derived = (InternalFolderObserver *)self;
1123 TnyFolderChangeChanged changed;
1125 changed = tny_folder_change_get_changed (change);
1127 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1130 /* Get added headers */
1131 list = tny_simple_list_new ();
1132 tny_folder_change_get_added_headers (change, list);
1134 /* Add them to the folder observer */
1135 tny_list_foreach (list, foreach_add_item,
1136 derived->new_headers);
1138 g_object_unref (G_OBJECT (list));
1143 internal_folder_observer_init (InternalFolderObserver *self)
1145 self->new_headers = tny_simple_list_new ();
1148 internal_folder_observer_finalize (GObject *object)
1150 InternalFolderObserver *self;
1152 self = (InternalFolderObserver *) object;
1153 g_object_unref (self->new_headers);
1155 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
1158 tny_folder_observer_init (TnyFolderObserverIface *iface)
1160 iface->update = internal_folder_observer_update;
1163 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
1165 GObjectClass *object_class;
1167 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
1168 object_class = (GObjectClass*) klass;
1169 object_class->finalize = internal_folder_observer_finalize;
1174 ModestMailOperation *mail_op;
1175 gchar *account_name;
1176 UpdateAccountCallback callback;
1181 TnyFolderObserver *inbox_observer;
1182 RetrieveAllCallback retrieve_all_cb;
1183 } UpdateAccountInfo;
1187 destroy_update_account_info (UpdateAccountInfo *info)
1189 g_free (info->account_name);
1190 g_object_unref (info->folders);
1191 g_object_unref (info->mail_op);
1192 g_slice_free (UpdateAccountInfo, info);
1196 update_account_get_msg_async_cb (TnyFolder *folder,
1202 GetMsgInfo *msg_info = (GetMsgInfo *) user_data;
1204 /* Just delete the helper. Don't do anything with the new
1205 msg. There is also no need to check for errors */
1206 g_object_unref (msg_info->mail_op);
1207 g_object_unref (msg_info->header);
1208 g_slice_free (GetMsgInfo, msg_info);
1212 inbox_refreshed_cb (TnyFolder *inbox,
1217 UpdateAccountInfo *info;
1218 ModestMailOperationPrivate *priv;
1219 TnyIterator *new_headers_iter;
1220 GPtrArray *new_headers_array = NULL;
1221 gint max_size, retrieve_limit, i;
1222 ModestAccountMgr *mgr;
1223 ModestAccountRetrieveType retrieve_type;
1224 TnyList *new_headers = NULL;
1225 gboolean headers_only, ignore_limit, succeeded;
1226 TnyTransportAccount *transport_account = NULL;
1228 info = (UpdateAccountInfo *) user_data;
1229 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1230 mgr = modest_runtime_get_account_mgr ();
1232 if (canceled || err || !inbox) {
1233 /* Try to send anyway */
1237 /* Get the message max size */
1238 max_size = modest_conf_get_int (modest_runtime_get_conf (),
1239 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1241 max_size = G_MAXINT;
1243 max_size = max_size * KB;
1245 /* Create the new headers array. We need it to sort the
1246 new headers by date */
1247 new_headers_array = g_ptr_array_new ();
1248 new_headers_iter = tny_list_create_iterator (((InternalFolderObserver *) info->inbox_observer)->new_headers);
1249 while (!tny_iterator_is_done (new_headers_iter)) {
1250 TnyHeader *header = NULL;
1252 header = TNY_HEADER (tny_iterator_get_current (new_headers_iter));
1253 /* Apply per-message size limits */
1254 if (tny_header_get_message_size (header) < max_size)
1255 g_ptr_array_add (new_headers_array, g_object_ref (header));
1257 g_object_unref (header);
1258 tny_iterator_next (new_headers_iter);
1260 g_object_unref (new_headers_iter);
1261 tny_folder_remove_observer (inbox, info->inbox_observer);
1262 g_object_unref (info->inbox_observer);
1263 info->inbox_observer = NULL;
1265 /* Update the last updated key, even if we don't have to get new headers */
1266 modest_account_mgr_set_last_updated (mgr, tny_account_get_id (priv->account), time (NULL));
1267 if (!canceled && !err)
1268 modest_account_mgr_set_server_account_username_has_succeeded (mgr, tny_account_get_id (priv->account), TRUE);
1270 if (new_headers_array->len == 0)
1273 /* Get per-account message amount retrieval limit */
1274 retrieve_limit = modest_account_mgr_get_retrieve_limit (mgr, info->account_name);
1275 if (retrieve_limit == 0)
1276 retrieve_limit = G_MAXINT;
1278 /* Get per-account retrieval type */
1279 retrieve_type = modest_account_mgr_get_retrieve_type (mgr, info->account_name);
1280 headers_only = (retrieve_type == MODEST_ACCOUNT_RETRIEVE_HEADERS_ONLY);
1283 g_ptr_array_sort (new_headers_array, (GCompareFunc) compare_headers_by_date);
1285 /* Ask the users if they want to retrieve all the messages
1286 even though the limit was exceeded */
1287 ignore_limit = FALSE;
1288 if (new_headers_array->len > retrieve_limit) {
1289 /* Ask the user if a callback has been specified and
1290 if the mail operation has a source (this means that
1291 was invoked by the user and not automatically by a
1293 if (info->retrieve_all_cb && priv->source)
1294 ignore_limit = info->retrieve_all_cb (priv->source,
1295 new_headers_array->len,
1299 if (!headers_only) {
1301 const gint msg_list_size = compute_message_array_size (new_headers_array);
1305 priv->total = new_headers_array->len;
1307 priv->total = MIN (new_headers_array->len, retrieve_limit);
1308 while (msg_num < priv->total) {
1309 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, msg_num));
1310 TnyFolder *folder = tny_header_get_folder (header);
1311 GetMsgInfo *msg_info;
1313 /* Create the message info */
1314 msg_info = g_slice_new0 (GetMsgInfo);
1315 msg_info->mail_op = g_object_ref (info->mail_op);
1316 msg_info->header = g_object_ref (header);
1317 msg_info->total_bytes = msg_list_size;
1319 /* Get message in an async way */
1320 tny_folder_get_msg_async (folder, header, update_account_get_msg_async_cb,
1321 get_msg_status_cb, msg_info);
1323 g_object_unref (folder);
1329 /* Copy the headers to a list and free the array */
1330 new_headers = tny_simple_list_new ();
1331 for (i=0; i < new_headers_array->len; i++) {
1332 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers_array, i));
1333 tny_list_append (new_headers, G_OBJECT (header));
1335 g_ptr_array_foreach (new_headers_array, (GFunc) g_object_unref, NULL);
1336 g_ptr_array_free (new_headers_array, FALSE);
1342 modest_account_mgr_set_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1343 tny_account_get_name (priv->account),
1346 /* Get the transport account */
1347 transport_account = (TnyTransportAccount *)
1348 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1349 info->account_name);
1351 if (transport_account) {
1352 ModestTnySendQueue *send_queue;
1356 send_queue = modest_runtime_get_send_queue (transport_account);
1357 g_object_unref (transport_account);
1359 /* Get outbox folder */
1360 outbox = tny_send_queue_get_outbox (TNY_SEND_QUEUE (send_queue));
1361 if (outbox) { /* this could fail in some cases */
1362 num_messages = tny_folder_get_all_count (outbox);
1363 g_object_unref (outbox);
1365 g_warning ("%s: could not get outbox", __FUNCTION__);
1369 if (num_messages != 0) {
1370 /* Reenable suspended items */
1371 modest_tny_send_queue_wakeup (MODEST_TNY_SEND_QUEUE (send_queue));
1374 tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE (send_queue));
1378 /* Check if the operation was a success */
1380 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1382 /* Set the account back to not busy */
1383 modest_account_mgr_set_account_busy (mgr, info->account_name, FALSE);
1385 /* Call the user callback */
1387 info->callback (info->mail_op, new_headers, info->user_data);
1389 /* Notify about operation end */
1390 modest_mail_operation_notify_end (info->mail_op);
1394 g_object_unref (new_headers);
1395 destroy_update_account_info (info);
1399 recurse_folders_async_cb (TnyFolderStore *folder_store,
1405 UpdateAccountInfo *info;
1406 ModestMailOperationPrivate *priv;
1408 info = (UpdateAccountInfo *) user_data;
1409 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1411 if (err || canceled) {
1412 /* Try to continue anyway */
1413 } else if (info->poke_all) {
1414 /* We're not getting INBOX children if we don't want to poke all */
1415 TnyIterator *iter = tny_list_create_iterator (list);
1416 while (!tny_iterator_is_done (iter)) {
1417 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1418 TnyList *folders = tny_simple_list_new ();
1420 /* Add to the list of all folders */
1421 tny_list_append (info->folders, (GObject *) folder);
1423 /* Add pending call */
1424 info->pending_calls++;
1426 tny_folder_store_get_folders_async (folder, folders, NULL,
1427 recurse_folders_async_cb,
1430 g_object_unref (G_OBJECT (folder));
1432 tny_iterator_next (iter);
1434 g_object_unref (G_OBJECT (iter));
1435 g_object_unref (G_OBJECT (list));
1438 /* Remove my own pending call */
1439 info->pending_calls--;
1441 /* This means that we have all the folders */
1442 if (info->pending_calls == 0) {
1443 TnyIterator *iter_all_folders;
1444 TnyFolder *inbox = NULL;
1446 iter_all_folders = tny_list_create_iterator (info->folders);
1448 /* Do a poke status over all folders */
1449 while (!tny_iterator_is_done (iter_all_folders) &&
1450 priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
1451 TnyFolder *folder = NULL;
1453 folder = TNY_FOLDER (tny_iterator_get_current (iter_all_folders));
1455 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX) {
1456 /* Get a reference to the INBOX */
1457 inbox = g_object_ref (folder);
1459 /* Issue a poke status over the folder */
1461 tny_folder_poke_status (folder);
1464 /* Free and go to next */
1465 g_object_unref (folder);
1466 tny_iterator_next (iter_all_folders);
1468 g_object_unref (iter_all_folders);
1470 /* Refresh the INBOX */
1472 /* Refresh the folder. Our observer receives
1473 * the new emails during folder refreshes, so
1474 * we can use observer->new_headers
1476 info->inbox_observer = g_object_new (internal_folder_observer_get_type (), NULL);
1477 tny_folder_add_observer (inbox, info->inbox_observer);
1479 /* Refresh the INBOX */
1480 tny_folder_refresh_async (inbox, inbox_refreshed_cb, NULL, info);
1481 g_object_unref (inbox);
1483 /* We could not perform the inbox refresh but
1484 we'll try to send mails anyway */
1485 inbox_refreshed_cb (inbox, FALSE, NULL, info);
1491 modest_mail_operation_update_account (ModestMailOperation *self,
1492 const gchar *account_name,
1494 RetrieveAllCallback retrieve_all_cb,
1495 UpdateAccountCallback callback,
1498 UpdateAccountInfo *info = NULL;
1499 ModestMailOperationPrivate *priv = NULL;
1500 ModestTnyAccountStore *account_store = NULL;
1502 ModestMailOperationState *state;
1504 /* Init mail operation */
1505 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1508 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1509 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE;
1511 /* Get the store account */
1512 account_store = modest_runtime_get_account_store ();
1514 modest_tny_account_store_get_server_account (account_store,
1516 TNY_ACCOUNT_TYPE_STORE);
1518 /* The above function could return NULL */
1519 if (!priv->account) {
1520 /* Check if the operation was a success */
1521 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1522 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1526 /* Call the user callback */
1528 callback (self, NULL, user_data);
1530 /* Notify about operation end */
1531 modest_mail_operation_notify_end (self);
1536 /* Create the helper object */
1537 info = g_slice_new0 (UpdateAccountInfo);
1538 info->pending_calls = 1;
1539 info->folders = tny_simple_list_new ();
1540 info->mail_op = g_object_ref (self);
1541 info->poke_all = poke_all;
1542 info->account_name = g_strdup (account_name);
1543 info->callback = callback;
1544 info->user_data = user_data;
1545 info->retrieve_all_cb = retrieve_all_cb;
1547 /* Set account busy */
1548 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr (), account_name, TRUE);
1549 modest_mail_operation_notify_start (self);
1551 /* notify about the start of the operation */
1552 state = modest_mail_operation_clone_state (self);
1556 /* Start notifying progress */
1557 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1558 g_slice_free (ModestMailOperationState, state);
1560 /* Get all folders and continue in the callback */
1561 folders = tny_simple_list_new ();
1562 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->account),
1564 recurse_folders_async_cb,
1569 * Used to notify the queue from the main
1570 * loop. We call it inside an idle call to achieve that
1573 idle_notify_queue (gpointer data)
1575 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1577 gdk_threads_enter ();
1578 modest_mail_operation_notify_end (mail_op);
1579 gdk_threads_leave ();
1580 g_object_unref (mail_op);
1586 compare_headers_by_date (gconstpointer a,
1589 TnyHeader **header1, **header2;
1590 time_t sent1, sent2;
1592 header1 = (TnyHeader **) a;
1593 header2 = (TnyHeader **) b;
1595 sent1 = tny_header_get_date_sent (*header1);
1596 sent2 = tny_header_get_date_sent (*header2);
1598 /* We want the most recent ones (greater time_t) at the
1607 /* ******************************************************************* */
1608 /* ************************** STORE ACTIONS ************************* */
1609 /* ******************************************************************* */
1612 ModestMailOperation *mail_op;
1613 CreateFolderUserCallback callback;
1619 create_folder_cb (TnyFolderStore *parent_folder,
1621 TnyFolder *new_folder,
1625 ModestMailOperationPrivate *priv;
1626 CreateFolderInfo *info;
1628 info = (CreateFolderInfo *) user_data;
1629 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1631 if (canceled || err) {
1632 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1634 priv->error = g_error_copy (err);
1636 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1637 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1640 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1643 /* The user will unref the new_folder */
1645 info->callback (info->mail_op, parent_folder,
1646 new_folder, info->user_data);
1648 /* Notify about operation end */
1649 modest_mail_operation_notify_end (info->mail_op);
1652 g_object_unref (info->mail_op);
1653 g_slice_free (CreateFolderInfo, info);
1657 modest_mail_operation_create_folder (ModestMailOperation *self,
1658 TnyFolderStore *parent,
1660 CreateFolderUserCallback callback,
1663 ModestMailOperationPrivate *priv;
1665 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1666 g_return_if_fail (name);
1668 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1669 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
1670 priv->account = (TNY_IS_ACCOUNT (parent)) ?
1671 g_object_ref (parent) :
1672 modest_tny_folder_get_account (TNY_FOLDER (parent));
1674 /* Check for already existing folder */
1675 if (modest_tny_folder_has_subfolder_with_name (parent, name, TRUE)) {
1676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1677 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1678 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1679 _CS("ckdg_ib_folder_already_exists"));
1683 if (TNY_IS_FOLDER (parent)) {
1684 /* Check folder rules */
1685 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1686 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1687 /* Set status failed and set an error */
1688 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1689 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1690 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1691 _("mail_in_ui_folder_create_error"));
1695 if (!strcmp (name, " ") || strchr (name, '/')) {
1696 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1697 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1698 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1699 _("mail_in_ui_folder_create_error"));
1703 CreateFolderInfo *info;
1705 info = g_slice_new0 (CreateFolderInfo);
1706 info->mail_op = g_object_ref (self);
1707 info->callback = callback;
1708 info->user_data = user_data;
1710 modest_mail_operation_notify_start (self);
1712 /* Create the folder */
1713 tny_folder_store_create_folder_async (parent, name, create_folder_cb,
1716 /* Call the user callback anyway */
1718 callback (self, parent, NULL, user_data);
1719 /* Notify about operation end */
1720 modest_mail_operation_notify_end (self);
1725 modest_mail_operation_remove_folder (ModestMailOperation *self,
1727 gboolean remove_to_trash)
1729 ModestMailOperationPrivate *priv;
1730 ModestTnyFolderRules rules;
1732 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1733 g_return_if_fail (TNY_IS_FOLDER (folder));
1735 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1737 /* Check folder rules */
1738 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1739 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1740 /* Set status failed and set an error */
1741 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1742 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1743 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1744 _("mail_in_ui_folder_delete_error"));
1748 /* Get the account */
1749 priv->account = modest_tny_folder_get_account (folder);
1750 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
1752 /* Delete folder or move to trash */
1753 if (remove_to_trash) {
1754 TnyFolder *trash_folder = NULL;
1755 trash_folder = modest_tny_account_get_special_folder (priv->account,
1756 TNY_FOLDER_TYPE_TRASH);
1757 /* TODO: error_handling */
1759 modest_mail_operation_notify_start (self);
1760 modest_mail_operation_xfer_folder (self, folder,
1761 TNY_FOLDER_STORE (trash_folder),
1763 g_object_unref (trash_folder);
1765 g_warning ("%s: modest_tny_account_get_special_folder(..) returned a NULL trash folder", __FUNCTION__);
1768 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1770 modest_mail_operation_notify_start (self);
1771 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1772 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1775 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1777 g_object_unref (parent);
1779 g_warning ("%s: could not get parent folder", __FUNCTION__);
1783 /* Notify about operation end */
1784 modest_mail_operation_notify_end (self);
1788 transfer_folder_status_cb (GObject *obj,
1792 ModestMailOperation *self;
1793 ModestMailOperationPrivate *priv;
1794 ModestMailOperationState *state;
1795 XFerFolderAsyncHelper *helper;
1797 g_return_if_fail (status != NULL);
1798 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1800 helper = (XFerFolderAsyncHelper *) user_data;
1801 g_return_if_fail (helper != NULL);
1803 self = helper->mail_op;
1804 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1806 priv->done = status->position;
1807 priv->total = status->of_total;
1809 state = modest_mail_operation_clone_state (self);
1811 /* This is not a GDK lock because we are a Tinymail callback
1812 * which is already GDK locked by Tinymail */
1814 /* no gdk_threads_enter (), CHECKED */
1816 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1818 /* no gdk_threads_leave (), CHECKED */
1820 g_slice_free (ModestMailOperationState, state);
1825 transfer_folder_cb (TnyFolder *folder,
1827 TnyFolderStore *into,
1828 TnyFolder *new_folder,
1832 XFerFolderAsyncHelper *helper;
1833 ModestMailOperation *self = NULL;
1834 ModestMailOperationPrivate *priv = NULL;
1836 helper = (XFerFolderAsyncHelper *) user_data;
1837 g_return_if_fail (helper != NULL);
1839 self = helper->mail_op;
1840 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1843 priv->error = g_error_copy (err);
1845 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1846 } else if (cancelled) {
1847 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1848 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1849 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1850 _("Transference of %s was cancelled."),
1851 tny_folder_get_name (folder));
1854 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1857 /* Notify about operation end */
1858 modest_mail_operation_notify_end (self);
1860 /* If user defined callback function was defined, call it */
1861 if (helper->user_callback) {
1863 /* This is not a GDK lock because we are a Tinymail callback
1864 * which is already GDK locked by Tinymail */
1866 /* no gdk_threads_enter (), CHECKED */
1867 helper->user_callback (self, new_folder, helper->user_data);
1868 /* no gdk_threads_leave () , CHECKED */
1872 g_object_unref (helper->mail_op);
1873 g_slice_free (XFerFolderAsyncHelper, helper);
1878 * This function checks if the new name is a valid name for our local
1879 * folders account. The new name could not be the same than then name
1880 * of any of the mandatory local folders
1882 * We can not rely on tinymail because tinymail does not check the
1883 * name of the virtual folders that the account could have in the case
1884 * that we're doing a rename (because it directly calls Camel which
1885 * knows nothing about our virtual folders).
1887 * In the case of an actual copy/move (i.e. move/copy a folder between
1888 * accounts) tinymail uses the tny_folder_store_create_account which
1889 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1890 * checks the new name of the folder, so this call in that case
1891 * wouldn't be needed. *But* NOTE that if tinymail changes its
1892 * implementation (if folder transfers within the same account is no
1893 * longer implemented as a rename) this call will allow Modest to work
1896 * If the new name is not valid, this function will set the status to
1897 * failed and will set also an error in the mail operation
1900 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1901 TnyFolderStore *into,
1902 const gchar *new_name)
1904 if (TNY_IS_ACCOUNT (into) &&
1905 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1906 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1908 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1909 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1910 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1911 _CS("ckdg_ib_folder_already_exists"));
1918 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1920 TnyFolderStore *parent,
1921 gboolean delete_original,
1922 XferFolderAsyncUserCallback user_callback,
1925 ModestMailOperationPrivate *priv = NULL;
1926 ModestTnyFolderRules parent_rules = 0, rules;
1927 XFerFolderAsyncHelper *helper = NULL;
1928 const gchar *folder_name = NULL;
1929 const gchar *error_msg;
1931 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1932 g_return_if_fail (TNY_IS_FOLDER (folder));
1933 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
1935 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1936 folder_name = tny_folder_get_name (folder);
1938 /* Set the error msg */
1939 error_msg = _("mail_in_ui_folder_move_target_error");
1941 /* Get account and set it into mail_operation */
1942 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1943 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1944 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1946 /* Get folder rules */
1947 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1948 if (TNY_IS_FOLDER (parent))
1949 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1951 /* Apply operation constraints */
1952 if ((gpointer) parent == (gpointer) folder ||
1953 (!TNY_IS_FOLDER_STORE (parent)) ||
1954 (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1957 } else if (TNY_IS_FOLDER (parent) &&
1958 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1962 } else if (TNY_IS_FOLDER (parent) &&
1963 TNY_IS_FOLDER_STORE (folder) &&
1964 modest_tny_folder_is_ancestor (TNY_FOLDER (parent),
1965 TNY_FOLDER_STORE (folder))) {
1966 /* Do not move a parent into a child */
1968 } else if (TNY_IS_FOLDER_STORE (parent) &&
1969 modest_tny_folder_has_subfolder_with_name (parent, folder_name, TRUE)) {
1970 /* Check that the new folder name is not used by any
1973 } else if (!(new_name_valid_if_local_account (priv, parent, folder_name))) {
1974 /* Check that the new folder name is not used by any
1975 special local folder */
1978 /* Create the helper */
1979 helper = g_slice_new0 (XFerFolderAsyncHelper);
1980 helper->mail_op = g_object_ref (self);
1981 helper->user_callback = user_callback;
1982 helper->user_data = user_data;
1984 /* Move/Copy folder */
1985 modest_mail_operation_notify_start (self);
1986 tny_folder_copy_async (folder,
1988 tny_folder_get_name (folder),
1991 transfer_folder_status_cb,
1997 /* Set status failed and set an error */
1998 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1999 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2000 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2003 /* Call the user callback if exists */
2005 user_callback (self, NULL, user_data);
2007 /* Notify the queue */
2008 modest_mail_operation_notify_end (self);
2012 modest_mail_operation_rename_folder (ModestMailOperation *self,
2015 XferFolderAsyncUserCallback user_callback,
2018 ModestMailOperationPrivate *priv;
2019 ModestTnyFolderRules rules;
2020 XFerFolderAsyncHelper *helper;
2022 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2023 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
2024 g_return_if_fail (name);
2026 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2028 /* Get account and set it into mail_operation */
2029 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2030 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
2032 /* Check folder rules */
2033 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2034 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
2036 } else if (!strcmp (name, " ") || strchr (name, '/')) {
2039 TnyFolderStore *into;
2041 into = tny_folder_get_folder_store (folder);
2043 /* Check that the new folder name is not used by any
2044 special local folder */
2045 if (new_name_valid_if_local_account (priv, into, name)) {
2046 /* Create the helper */
2047 helper = g_slice_new0 (XFerFolderAsyncHelper);
2048 helper->mail_op = g_object_ref(self);
2049 helper->user_callback = user_callback;
2050 helper->user_data = user_data;
2052 /* Rename. Camel handles folder subscription/unsubscription */
2053 modest_mail_operation_notify_start (self);
2054 tny_folder_copy_async (folder, into, name, TRUE,
2056 transfer_folder_status_cb,
2061 g_object_unref (into);
2066 /* Set status failed and set an error */
2067 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2068 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2069 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2070 _("FIXME: unable to rename"));
2073 user_callback (self, NULL, user_data);
2075 /* Notify about operation end */
2076 modest_mail_operation_notify_end (self);
2079 /* ******************************************************************* */
2080 /* ************************** MSG ACTIONS ************************* */
2081 /* ******************************************************************* */
2084 modest_mail_operation_get_msg (ModestMailOperation *self,
2086 GetMsgAsyncUserCallback user_callback,
2089 GetMsgInfo *helper = NULL;
2091 ModestMailOperationPrivate *priv;
2093 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2094 g_return_if_fail (TNY_IS_HEADER (header));
2096 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2097 folder = tny_header_get_folder (header);
2099 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2103 /* Get account and set it into mail_operation */
2104 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2106 /* Check for cached messages */
2107 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)
2108 priv->op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
2110 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2112 /* Create the helper */
2113 helper = g_slice_new0 (GetMsgInfo);
2114 helper->header = g_object_ref (header);
2115 helper->mail_op = g_object_ref (self);
2116 helper->user_callback = user_callback;
2117 helper->user_data = user_data;
2118 helper->destroy_notify = NULL;
2119 helper->last_total_bytes = 0;
2120 helper->sum_total_bytes = 0;
2121 helper->total_bytes = tny_header_get_message_size (header);
2123 modest_mail_operation_notify_start (self);
2125 /* notify about the start of the operation */
2126 ModestMailOperationState *state;
2127 state = modest_mail_operation_clone_state (self);
2130 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2133 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, helper);
2135 g_object_unref (G_OBJECT (folder));
2139 get_msg_status_cb (GObject *obj,
2143 GetMsgInfo *helper = NULL;
2145 g_return_if_fail (status != NULL);
2146 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2148 helper = (GetMsgInfo *) user_data;
2149 g_return_if_fail (helper != NULL);
2151 /* Notify progress */
2152 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2153 &(helper->sum_total_bytes), helper->total_bytes, FALSE);
2157 get_msg_async_cb (TnyFolder *folder,
2163 GetMsgInfo *info = NULL;
2164 ModestMailOperationPrivate *priv = NULL;
2167 info = (GetMsgInfo *) user_data;
2169 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2172 if (info->more_msgs) {
2173 tny_iterator_next (info->more_msgs);
2174 finished = (tny_iterator_is_done (info->more_msgs));
2176 finished = (priv->done == priv->total) ? TRUE : FALSE;
2179 /* If canceled by the user, ignore the error given by Tinymail */
2180 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2183 } else if (canceled || err) {
2184 priv->status = MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS;
2186 priv->error = g_error_copy ((const GError *) err);
2187 priv->error->domain = MODEST_MAIL_OPERATION_ERROR;
2190 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2191 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2194 } else if (finished && priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS) {
2195 /* Set the success status before calling the user callback */
2196 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2200 /* Call the user callback */
2201 if (info->user_callback)
2202 info->user_callback (info->mail_op, info->header, canceled,
2203 msg, err, info->user_data);
2205 /* Notify about operation end if this is the last callback */
2207 /* Free user data */
2208 if (info->destroy_notify)
2209 info->destroy_notify (info->user_data);
2211 /* Notify about operation end */
2212 modest_mail_operation_notify_end (info->mail_op);
2215 if (info->more_msgs)
2216 g_object_unref (info->more_msgs);
2217 g_object_unref (info->header);
2218 g_object_unref (info->mail_op);
2219 g_slice_free (GetMsgInfo, info);
2220 } else if (info->more_msgs) {
2221 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (info->more_msgs));
2222 TnyFolder *folder = tny_header_get_folder (header);
2224 g_object_unref (info->header);
2225 info->header = g_object_ref (header);
2227 /* Retrieve the next message */
2228 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, info);
2230 g_object_unref (header);
2231 g_object_unref (folder);
2233 g_warning ("%s: finished != TRUE but no messages left", __FUNCTION__);
2238 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2239 TnyList *header_list,
2240 GetMsgAsyncUserCallback user_callback,
2242 GDestroyNotify notify)
2244 ModestMailOperationPrivate *priv = NULL;
2246 TnyIterator *iter = NULL;
2247 gboolean has_uncached_messages;
2249 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2251 /* Init mail operation */
2252 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2253 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2255 priv->total = tny_list_get_length(header_list);
2257 /* Check uncached messages */
2258 for (iter = tny_list_create_iterator (header_list), has_uncached_messages = FALSE;
2259 !has_uncached_messages && !tny_iterator_is_done (iter);
2260 tny_iterator_next (iter)) {
2263 header = (TnyHeader *) tny_iterator_get_current (iter);
2264 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
2265 has_uncached_messages = TRUE;
2266 g_object_unref (header);
2268 priv->op_type = has_uncached_messages?MODEST_MAIL_OPERATION_TYPE_RECEIVE:MODEST_MAIL_OPERATION_TYPE_OPEN;
2270 /* Get account and set it into mail_operation */
2271 if (tny_list_get_length (header_list) >= 1) {
2272 TnyIterator *iterator = tny_list_create_iterator (header_list);
2273 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iterator));
2275 TnyFolder *folder = tny_header_get_folder (header);
2277 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2278 g_object_unref (folder);
2280 g_object_unref (header);
2282 g_object_unref (iterator);
2285 msg_list_size = compute_message_list_size (header_list);
2287 modest_mail_operation_notify_start (self);
2288 iter = tny_list_create_iterator (header_list);
2289 if (!tny_iterator_is_done (iter)) {
2290 /* notify about the start of the operation */
2291 ModestMailOperationState *state;
2292 state = modest_mail_operation_clone_state (self);
2295 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2298 GetMsgInfo *msg_info = NULL;
2299 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2300 TnyFolder *folder = tny_header_get_folder (header);
2302 /* Create the message info */
2303 msg_info = g_slice_new0 (GetMsgInfo);
2304 msg_info->mail_op = g_object_ref (self);
2305 msg_info->header = g_object_ref (header);
2306 msg_info->more_msgs = g_object_ref (iter);
2307 msg_info->user_callback = user_callback;
2308 msg_info->user_data = user_data;
2309 msg_info->destroy_notify = notify;
2310 msg_info->last_total_bytes = 0;
2311 msg_info->sum_total_bytes = 0;
2312 msg_info->total_bytes = msg_list_size;
2314 /* The callback will call it per each header */
2315 tny_folder_get_msg_async (folder, header, get_msg_async_cb, get_msg_status_cb, msg_info);
2317 /* Free and go on */
2318 g_object_unref (header);
2319 g_object_unref (folder);
2320 g_slice_free (ModestMailOperationState, state);
2322 g_object_unref (iter);
2327 modest_mail_operation_remove_msg (ModestMailOperation *self,
2329 gboolean remove_to_trash /*ignored*/)
2332 ModestMailOperationPrivate *priv;
2334 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2335 g_return_if_fail (TNY_IS_HEADER (header));
2337 if (remove_to_trash)
2338 g_warning ("remove to trash is not implemented");
2340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2341 folder = tny_header_get_folder (header);
2343 /* Get account and set it into mail_operation */
2344 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2345 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2348 /* remove message from folder */
2349 tny_folder_remove_msg (folder, header, &(priv->error));
2351 gboolean expunge, leave_on_server;
2352 const gchar *account_name;
2353 TnyAccount *account;
2354 ModestTransportStoreProtocol account_proto;
2356 tny_header_set_flag (header, TNY_HEADER_FLAG_DELETED);
2357 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2359 modest_mail_operation_notify_start (self);
2361 /* Get leave on server setting */
2362 account = tny_folder_get_account (folder);
2363 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2365 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2368 account_proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
2370 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2371 modest_tny_folder_is_remote_folder (folder) == FALSE)
2377 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2380 g_object_unref (account);
2386 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2388 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2391 g_object_unref (G_OBJECT (folder));
2393 /* Notify about operation end */
2394 modest_mail_operation_notify_end (self);
2398 modest_mail_operation_remove_msgs (ModestMailOperation *self,
2400 gboolean remove_to_trash /*ignored*/)
2402 TnyFolder *folder = NULL;
2403 ModestMailOperationPrivate *priv;
2404 TnyIterator *iter = NULL;
2405 TnyHeader *header = NULL;
2406 TnyList *remove_headers = NULL;
2407 TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2409 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2410 g_return_if_fail (TNY_IS_LIST (headers));
2412 if (remove_to_trash)
2413 g_warning ("remove to trash is not implemented");
2415 if (tny_list_get_length(headers) == 0) {
2416 g_warning ("%s: list of headers is empty\n", __FUNCTION__);
2417 goto cleanup; /* nothing to do */
2420 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2421 remove_headers = g_object_ref(headers);
2423 /* Get folder from first header and sync it */
2424 iter = tny_list_create_iterator (headers);
2425 header = TNY_HEADER (tny_iterator_get_current (iter));
2427 folder = tny_header_get_folder (header);
2428 if (!TNY_IS_FOLDER(folder)) {
2429 g_warning ("%s: could not get folder for header\n", __FUNCTION__);
2433 /* Don't remove messages that are being sent */
2434 if (modest_tny_folder_is_local_folder (folder)) {
2435 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
2437 if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2438 TnyTransportAccount *traccount = NULL;
2439 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
2440 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
2442 ModestTnySendQueueStatus status;
2443 ModestTnySendQueue *send_queue = modest_runtime_get_send_queue(traccount);
2444 TnyIterator *iter = tny_list_create_iterator(headers);
2445 g_object_unref(remove_headers);
2446 remove_headers = TNY_LIST(tny_simple_list_new());
2447 while (!tny_iterator_is_done(iter)) {
2449 TnyHeader *hdr = TNY_HEADER(tny_iterator_get_current(iter));
2450 msg_id = modest_tny_send_queue_get_msg_id (hdr);
2451 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2452 if (status != MODEST_TNY_SEND_QUEUE_SENDING) {
2453 tny_list_append(remove_headers, G_OBJECT(hdr));
2455 g_object_unref(hdr);
2457 tny_iterator_next(iter);
2459 g_object_unref(iter);
2460 g_object_unref(traccount);
2464 /* Get account and set it into mail_operation */
2465 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2466 priv->op_type = MODEST_MAIL_OPERATION_TYPE_DELETE;
2467 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2469 /* remove message from folder */
2470 modest_mail_operation_notify_start (self);
2472 tny_folder_remove_msgs (folder, remove_headers, &(priv->error));
2474 gboolean expunge, leave_on_server;
2475 const gchar *account_name;
2477 TnyAccount *account;
2478 ModestTransportStoreProtocol account_proto = MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
2480 account = tny_folder_get_account (folder);
2481 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2483 modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2486 proto = tny_account_get_proto (account);
2488 account_proto = modest_protocol_info_get_transport_store_protocol (proto);
2491 if (((account_proto == MODEST_PROTOCOL_STORE_POP) && !leave_on_server) ||
2492 modest_tny_folder_is_remote_folder (folder) == FALSE)
2498 tny_folder_sync_async(folder, expunge, NULL, NULL, NULL);
2500 g_object_unref (account);
2506 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2508 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2513 g_object_unref (remove_headers);
2515 g_object_unref (header);
2517 g_object_unref (iter);
2519 g_object_unref (folder);
2521 /* Notify about operation end */
2522 modest_mail_operation_notify_end (self);
2526 notify_progress_of_multiple_messages (ModestMailOperation *self,
2528 gint *last_total_bytes,
2529 gint *sum_total_bytes,
2531 gboolean increment_done)
2533 ModestMailOperationPrivate *priv;
2534 ModestMailOperationState *state;
2535 gboolean is_num_bytes = FALSE;
2537 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2539 /* We know that tinymail sends us information about
2540 * transferred bytes with this particular message
2542 * (FIXME: this is very ugly, and no I (djcb) didn't write this code,
2543 * I just added the 'if' so we don't get runtime warning)
2545 if (status->message)
2546 is_num_bytes = (g_ascii_strcasecmp (status->message, "Retrieving message") == 0);
2548 state = modest_mail_operation_clone_state (self);
2549 if (is_num_bytes && !((status->position == 1) && (status->of_total == 100))) {
2550 /* We know that we're in a different message when the
2551 total number of bytes to transfer is different. Of
2552 course it could fail if we're transferring messages
2553 of the same size, but this is a workarround */
2554 if (status->of_total != *last_total_bytes) {
2555 /* We need to increment the done when there is
2556 no information about each individual
2557 message, we need to do this in message
2558 transfers, and we don't do it for getting
2562 *sum_total_bytes += *last_total_bytes;
2563 *last_total_bytes = status->of_total;
2565 state->bytes_done += status->position + *sum_total_bytes;
2566 state->bytes_total = total_bytes;
2568 /* Notify the status change. Only notify about changes
2569 referred to bytes */
2570 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2574 g_slice_free (ModestMailOperationState, state);
2578 transfer_msgs_status_cb (GObject *obj,
2582 XFerMsgsAsyncHelper *helper;
2584 g_return_if_fail (status != NULL);
2585 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2587 helper = (XFerMsgsAsyncHelper *) user_data;
2588 g_return_if_fail (helper != NULL);
2590 /* Notify progress */
2591 notify_progress_of_multiple_messages (helper->mail_op, status, &(helper->last_total_bytes),
2592 &(helper->sum_total_bytes), helper->total_bytes, TRUE);
2597 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError *err, gpointer user_data)
2599 XFerMsgsAsyncHelper *helper;
2600 ModestMailOperation *self;
2601 ModestMailOperationPrivate *priv;
2602 gboolean finished = TRUE;
2604 helper = (XFerMsgsAsyncHelper *) user_data;
2605 self = helper->mail_op;
2607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2610 priv->error = g_error_copy (err);
2612 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2613 } else if (cancelled) {
2614 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2615 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2616 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2617 _("Error trying to refresh the contents of %s"),
2618 tny_folder_get_name (folder));
2619 } else if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2620 if (helper->more_msgs) {
2621 /* We'll transfer the next message in the list */
2622 tny_iterator_next (helper->more_msgs);
2623 if (!tny_iterator_is_done (helper->more_msgs)) {
2624 GObject *next_header;
2625 g_object_unref (helper->headers);
2626 helper->headers = tny_simple_list_new ();
2627 next_header = tny_iterator_get_current (helper->more_msgs);
2628 tny_list_append (helper->headers, next_header);
2629 g_object_unref (next_header);
2636 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2642 /* Update folder counts */
2643 tny_folder_poke_status (folder);
2644 tny_folder_poke_status (helper->dest_folder);
2646 /* Notify about operation end */
2647 modest_mail_operation_notify_end (self);
2649 /* If user defined callback function was defined, call it */
2650 if (helper->user_callback) {
2651 /* This is not a GDK lock because we are a Tinymail callback and
2652 * Tinymail already acquires the Gdk lock */
2654 /* no gdk_threads_enter (), CHECKED */
2655 helper->user_callback (self, helper->user_data);
2656 /* no gdk_threads_leave (), CHECKED */
2660 if (helper->more_msgs)
2661 g_object_unref (helper->more_msgs);
2662 if (helper->headers)
2663 g_object_unref (helper->headers);
2664 if (helper->dest_folder)
2665 g_object_unref (helper->dest_folder);
2666 if (helper->mail_op)
2667 g_object_unref (helper->mail_op);
2668 g_slice_free (XFerMsgsAsyncHelper, helper);
2670 /* Transfer more messages */
2671 tny_folder_transfer_msgs_async (folder,
2673 helper->dest_folder,
2676 transfer_msgs_status_cb,
2682 compute_message_list_size (TnyList *headers)
2687 iter = tny_list_create_iterator (headers);
2688 while (!tny_iterator_is_done (iter)) {
2689 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2690 size += tny_header_get_message_size (header);
2691 g_object_unref (header);
2692 tny_iterator_next (iter);
2694 g_object_unref (iter);
2700 compute_message_array_size (GPtrArray *headers)
2705 for (i = 0; i < headers->len; i++) {
2706 TnyHeader *header = TNY_HEADER (g_ptr_array_index (headers, i));
2707 size += tny_header_get_message_size (header);
2715 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2718 gboolean delete_original,
2719 XferMsgsAsyncUserCallback user_callback,
2722 ModestMailOperationPrivate *priv = NULL;
2723 TnyIterator *iter = NULL;
2724 TnyFolder *src_folder = NULL;
2725 XFerMsgsAsyncHelper *helper = NULL;
2726 TnyHeader *header = NULL;
2727 ModestTnyFolderRules rules = 0;
2728 TnyAccount *dst_account = NULL;
2729 gboolean leave_on_server;
2731 g_return_if_fail (self && MODEST_IS_MAIL_OPERATION (self));
2732 g_return_if_fail (headers && TNY_IS_LIST (headers));
2733 g_return_if_fail (folder && TNY_IS_FOLDER (folder));
2735 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2736 priv->total = tny_list_get_length (headers);
2738 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2739 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2741 /* Apply folder rules */
2742 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2743 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2744 /* Set status failed and set an error */
2745 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2746 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2747 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2748 _CS("ckct_ib_unable_to_paste_here"));
2749 /* Notify the queue */
2750 modest_mail_operation_notify_end (self);
2754 /* Get source folder */
2755 iter = tny_list_create_iterator (headers);
2756 header = TNY_HEADER (tny_iterator_get_current (iter));
2758 src_folder = tny_header_get_folder (header);
2759 g_object_unref (header);
2761 g_object_unref (iter);
2763 if (src_folder == NULL) {
2764 /* Notify the queue */
2765 modest_mail_operation_notify_end (self);
2767 g_warning ("%s: cannot find folder from header", __FUNCTION__);
2772 /* Check folder source and destination */
2773 if (src_folder == folder) {
2774 /* Set status failed and set an error */
2775 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2776 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2777 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2778 _("mail_in_ui_folder_copy_target_error"));
2780 /* Notify the queue */
2781 modest_mail_operation_notify_end (self);
2784 g_object_unref (src_folder);
2788 /* Create the helper */
2789 helper = g_slice_new0 (XFerMsgsAsyncHelper);
2790 helper->mail_op = g_object_ref(self);
2791 helper->dest_folder = g_object_ref(folder);
2792 helper->user_callback = user_callback;
2793 helper->user_data = user_data;
2794 helper->delete = delete_original;
2795 helper->last_total_bytes = 0;
2796 helper->sum_total_bytes = 0;
2797 helper->total_bytes = compute_message_list_size (headers);
2799 /* Get account and set it into mail_operation */
2800 priv->account = modest_tny_folder_get_account (src_folder);
2801 dst_account = modest_tny_folder_get_account (folder);
2803 if (priv->account == dst_account) {
2804 /* Transfer all messages at once using the fast
2805 * method. Note that depending on the server this
2806 * might not be that fast, and might not be
2807 * user-cancellable either */
2808 helper->headers = g_object_ref (headers);
2809 helper->more_msgs = NULL;
2811 /* Transfer messages one by one so the user can cancel
2814 helper->headers = tny_simple_list_new ();
2815 helper->more_msgs = tny_list_create_iterator (headers);
2816 hdr = tny_iterator_get_current (helper->more_msgs);
2817 tny_list_append (helper->headers, hdr);
2818 g_object_unref (hdr);
2821 /* If leave_on_server is set to TRUE then don't use
2822 delete_original, we always pass FALSE. This is because
2823 otherwise tinymail will try to sync the source folder and
2824 this could cause an error if we're offline while
2825 transferring an already downloaded message from a POP
2827 if (modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (priv->account)) ==
2828 MODEST_PROTOCOL_STORE_POP) {
2829 const gchar *account_name;
2831 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (priv->account);
2832 leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
2835 leave_on_server = FALSE;
2838 modest_mail_operation_notify_start (self);
2839 tny_folder_transfer_msgs_async (src_folder,
2842 (leave_on_server) ? FALSE : delete_original,
2844 transfer_msgs_status_cb,
2846 g_object_unref (src_folder);
2847 g_object_unref (dst_account);
2852 on_refresh_folder (TnyFolder *folder,
2857 RefreshAsyncHelper *helper = NULL;
2858 ModestMailOperation *self = NULL;
2859 ModestMailOperationPrivate *priv = NULL;
2861 helper = (RefreshAsyncHelper *) user_data;
2862 self = helper->mail_op;
2863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2865 g_return_if_fail(priv!=NULL);
2868 priv->error = g_error_copy (error);
2869 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2874 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2875 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2876 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2877 _("Error trying to refresh the contents of %s"),
2878 tny_folder_get_name (folder));
2882 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2885 /* Call user defined callback, if it exists */
2886 if (helper->user_callback) {
2888 /* This is not a GDK lock because we are a Tinymail callback and
2889 * Tinymail already acquires the Gdk lock */
2890 helper->user_callback (self, folder, helper->user_data);
2894 g_slice_free (RefreshAsyncHelper, helper);
2896 /* Notify about operation end */
2897 modest_mail_operation_notify_end (self);
2898 g_object_unref(self);
2902 on_refresh_folder_status_update (GObject *obj,
2906 RefreshAsyncHelper *helper = NULL;
2907 ModestMailOperation *self = NULL;
2908 ModestMailOperationPrivate *priv = NULL;
2909 ModestMailOperationState *state;
2911 g_return_if_fail (user_data != NULL);
2912 g_return_if_fail (status != NULL);
2913 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2915 helper = (RefreshAsyncHelper *) user_data;
2916 self = helper->mail_op;
2917 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2919 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2921 priv->done = status->position;
2922 priv->total = status->of_total;
2924 state = modest_mail_operation_clone_state (self);
2926 /* This is not a GDK lock because we are a Tinymail callback and
2927 * Tinymail already acquires the Gdk lock */
2928 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2930 g_slice_free (ModestMailOperationState, state);
2934 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2936 RefreshAsyncUserCallback user_callback,
2939 ModestMailOperationPrivate *priv = NULL;
2940 RefreshAsyncHelper *helper = NULL;
2942 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2944 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2946 /* Get account and set it into mail_operation */
2947 priv->account = modest_tny_folder_get_account (folder);
2948 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
2950 /* Create the helper */
2951 helper = g_slice_new0 (RefreshAsyncHelper);
2952 helper->mail_op = g_object_ref(self);
2953 helper->user_callback = user_callback;
2954 helper->user_data = user_data;
2956 modest_mail_operation_notify_start (self);
2958 /* notify that the operation was started */
2959 ModestMailOperationState *state;
2960 state = modest_mail_operation_clone_state (self);
2963 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL],
2966 /* FIXME: we're leaking the state here, or? valgrind thinks so */
2968 tny_folder_refresh_async (folder,
2970 on_refresh_folder_status_update,
2975 run_queue_stop (ModestTnySendQueue *queue,
2976 ModestMailOperation *self)
2978 ModestMailOperationPrivate *priv;
2980 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2981 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2982 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2984 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2986 modest_mail_operation_notify_end (self);
2987 g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self);
2988 g_object_unref (self);
2991 modest_mail_operation_run_queue (ModestMailOperation *self,
2992 ModestTnySendQueue *queue)
2994 ModestMailOperationPrivate *priv;
2996 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2997 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (queue));
2998 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3000 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3001 priv->account = TNY_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (queue)));
3002 priv->op_type = MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE;
3004 modest_mail_operation_notify_start (self);
3005 g_object_ref (self);
3006 g_signal_connect ((gpointer) queue, "queue-stop", G_CALLBACK (run_queue_stop), (gpointer) self);
3010 sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, ModestMailOperation *mail_op)
3012 ModestMailOperationPrivate *priv;
3014 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_op);
3016 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
3017 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
3019 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
3021 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3023 modest_mail_operation_notify_end (mail_op);
3024 g_object_unref (mail_op);
3028 modest_mail_operation_sync_folder (ModestMailOperation *self,
3029 TnyFolder *folder, gboolean expunge)
3031 ModestMailOperationPrivate *priv;
3033 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
3034 g_return_if_fail (TNY_IS_FOLDER (folder));
3035 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
3037 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
3038 priv->account = TNY_ACCOUNT (tny_folder_get_account (folder));
3039 priv->op_type = MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER;
3041 modest_mail_operation_notify_start (self);
3042 g_object_ref (self);
3043 tny_folder_sync_async (folder, expunge, (TnyFolderCallback) sync_folder_finish_callback, NULL, self);
3047 modest_mail_operation_notify_start (ModestMailOperation *self)
3049 ModestMailOperationPrivate *priv = NULL;
3051 g_return_if_fail (self);
3053 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3055 /* Ensure that all the fields are filled correctly */
3056 g_return_if_fail (priv->op_type != MODEST_MAIL_OPERATION_TYPE_UNKNOWN);
3058 /* Notify the observers about the mail operation. We do not
3059 wrapp this emission because we assume that this function is
3060 always called from within the main lock */
3061 g_signal_emit (G_OBJECT (self), signals[OPERATION_STARTED_SIGNAL], 0, NULL);
3066 * It's used by the mail operation queue to notify the observers
3067 * attached to that signal that the operation finished. We need to use
3068 * that because tinymail does not give us the progress of a given
3069 * operation when it finishes (it directly calls the operation
3073 modest_mail_operation_notify_end (ModestMailOperation *self)
3075 ModestMailOperationPrivate *priv = NULL;
3077 g_return_if_fail (self);
3079 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3081 /* Notify the observers about the mail operation end. We do
3082 not wrapp this emission because we assume that this
3083 function is always called from within the main lock */
3084 g_signal_emit (G_OBJECT (self), signals[OPERATION_FINISHED_SIGNAL], 0, NULL);
3086 /* Remove the error user data */
3087 if (priv->error_checking_user_data && priv->error_checking_user_data_destroyer)
3088 priv->error_checking_user_data_destroyer (priv->error_checking_user_data);
3092 modest_mail_operation_get_account (ModestMailOperation *self)
3094 ModestMailOperationPrivate *priv = NULL;
3096 g_return_val_if_fail (self, NULL);
3098 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3100 return (priv->account) ? g_object_ref (priv->account) : NULL;
3104 modest_mail_operation_noop (ModestMailOperation *self)
3106 ModestMailOperationPrivate *priv = NULL;
3108 g_return_if_fail (self);
3110 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3111 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
3112 priv->op_type = MODEST_MAIL_OPERATION_TYPE_INFO;
3116 /* This mail operation does nothing actually */
3117 modest_mail_operation_notify_start (self);
3118 modest_mail_operation_notify_end (self);
3123 modest_mail_operation_to_string (ModestMailOperation *self)
3125 const gchar *type, *status, *account_id;
3126 ModestMailOperationPrivate *priv = NULL;
3128 g_return_val_if_fail (self, NULL);
3130 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
3132 /* new operations don't have anything interesting */
3133 if (priv->op_type == MODEST_MAIL_OPERATION_TYPE_UNKNOWN)
3134 return g_strdup_printf ("%p <new operation>", self);
3136 switch (priv->op_type) {
3137 case MODEST_MAIL_OPERATION_TYPE_SEND: type= "SEND"; break;
3138 case MODEST_MAIL_OPERATION_TYPE_RECEIVE: type= "RECEIVE"; break;
3139 case MODEST_MAIL_OPERATION_TYPE_OPEN: type= "OPEN"; break;
3140 case MODEST_MAIL_OPERATION_TYPE_DELETE: type= "DELETE"; break;
3141 case MODEST_MAIL_OPERATION_TYPE_INFO: type= "INFO"; break;
3142 case MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE: type= "RUN-QUEUE"; break;
3143 case MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER: type= "SYNC-FOLDER"; break;
3144 case MODEST_MAIL_OPERATION_TYPE_UNKNOWN: type= "UNKNOWN"; break;
3145 default: type = "UNEXPECTED"; break;
3148 switch (priv->status) {
3149 case MODEST_MAIL_OPERATION_STATUS_INVALID: status= "INVALID"; break;
3150 case MODEST_MAIL_OPERATION_STATUS_SUCCESS: status= "SUCCESS"; break;
3151 case MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS: status= "FINISHED-WITH-ERRORS"; break;
3152 case MODEST_MAIL_OPERATION_STATUS_FAILED: status= "FAILED"; break;
3153 case MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS: status= "IN-PROGRESS"; break;
3154 case MODEST_MAIL_OPERATION_STATUS_CANCELED: status= "CANCELLED"; break;
3155 default: status= "UNEXPECTED"; break;
3158 account_id = priv->account ? tny_account_get_id (priv->account) : "";
3160 return g_strdup_printf ("%p \"%s\" (%s) [%s] {%d/%d} '%s'", self, account_id,type, status,
3161 priv->done, priv->total,
3162 priv->error && priv->error->message ? priv->error->message : "");