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-tny-account.h>
49 #include <modest-tny-send-queue.h>
50 #include <modest-runtime.h>
51 #include "modest-text-utils.h"
52 #include "modest-tny-msg.h"
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account-store.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-marshal.h"
57 #include "modest-error.h"
58 #include "modest-mail-operation.h"
61 #define GET_SIZE_BUFFER_SIZE 128
64 * Remove all these #ifdef stuff when the tinymail's idle calls become
67 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
69 /* 'private'/'protected' functions */
70 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
71 static void modest_mail_operation_init (ModestMailOperation *obj);
72 static void modest_mail_operation_finalize (GObject *obj);
74 static void get_msg_cb (TnyFolder *folder,
80 static void get_msg_status_cb (GObject *obj,
84 static void modest_mail_operation_notify_end (ModestMailOperation *self);
86 static gboolean did_a_cancel = FALSE;
88 enum _ModestMailOperationSignals
90 PROGRESS_CHANGED_SIGNAL,
95 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
96 struct _ModestMailOperationPrivate {
103 ErrorCheckingUserCallback error_checking;
104 gpointer error_checking_user_data;
105 ModestMailOperationStatus status;
106 ModestMailOperationTypeOperation op_type;
109 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
110 MODEST_TYPE_MAIL_OPERATION, \
111 ModestMailOperationPrivate))
113 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
114 priv->status = new_status;\
117 typedef struct _GetMsgAsyncHelper {
118 ModestMailOperation *mail_op;
120 GetMsgAsyncUserCallback user_callback;
124 typedef struct _RefreshAsyncHelper {
125 ModestMailOperation *mail_op;
126 RefreshAsyncUserCallback user_callback;
128 } RefreshAsyncHelper;
130 typedef struct _XFerMsgAsyncHelper
132 ModestMailOperation *mail_op;
134 TnyFolder *dest_folder;
135 XferMsgsAsynUserCallback user_callback;
137 } XFerMsgAsyncHelper;
139 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
143 static void modest_mail_operation_create_msg (ModestMailOperation *self,
144 const gchar *from, const gchar *to,
145 const gchar *cc, const gchar *bcc,
146 const gchar *subject, const gchar *plain_body,
147 const gchar *html_body, const GList *attachments_list,
148 TnyHeaderFlags priority_flags,
149 ModestMailOperationCreateMsgCallback callback,
152 static gboolean idle_notify_queue (gpointer data);
155 ModestMailOperation *mail_op;
163 GList *attachments_list;
164 TnyHeaderFlags priority_flags;
165 ModestMailOperationCreateMsgCallback callback;
171 ModestMailOperation *mail_op;
173 ModestMailOperationCreateMsgCallback callback;
178 static GObjectClass *parent_class = NULL;
180 static guint signals[NUM_SIGNALS] = {0};
183 modest_mail_operation_get_type (void)
185 static GType my_type = 0;
187 static const GTypeInfo my_info = {
188 sizeof(ModestMailOperationClass),
189 NULL, /* base init */
190 NULL, /* base finalize */
191 (GClassInitFunc) modest_mail_operation_class_init,
192 NULL, /* class finalize */
193 NULL, /* class data */
194 sizeof(ModestMailOperation),
196 (GInstanceInitFunc) modest_mail_operation_init,
199 my_type = g_type_register_static (G_TYPE_OBJECT,
200 "ModestMailOperation",
207 modest_mail_operation_class_init (ModestMailOperationClass *klass)
209 GObjectClass *gobject_class;
210 gobject_class = (GObjectClass*) klass;
212 parent_class = g_type_class_peek_parent (klass);
213 gobject_class->finalize = modest_mail_operation_finalize;
215 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
218 * ModestMailOperation::progress-changed
219 * @self: the #MailOperation that emits the signal
220 * @user_data: user data set when the signal handler was connected
222 * Emitted when the progress of a mail operation changes
224 signals[PROGRESS_CHANGED_SIGNAL] =
225 g_signal_new ("progress-changed",
226 G_TYPE_FROM_CLASS (gobject_class),
228 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
230 g_cclosure_marshal_VOID__POINTER,
231 G_TYPE_NONE, 1, G_TYPE_POINTER);
236 modest_mail_operation_init (ModestMailOperation *obj)
238 ModestMailOperationPrivate *priv;
240 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
242 priv->account = NULL;
243 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
244 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
249 priv->error_checking = NULL;
250 priv->error_checking_user_data = NULL;
254 modest_mail_operation_finalize (GObject *obj)
256 ModestMailOperationPrivate *priv;
258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
263 g_error_free (priv->error);
267 g_object_unref (priv->source);
271 g_object_unref (priv->account);
272 priv->account = NULL;
276 G_OBJECT_CLASS(parent_class)->finalize (obj);
280 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
283 ModestMailOperation *obj;
284 ModestMailOperationPrivate *priv;
286 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
287 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
289 priv->op_type = op_type;
291 priv->source = g_object_ref(source);
297 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
299 ErrorCheckingUserCallback error_handler,
302 ModestMailOperation *obj;
303 ModestMailOperationPrivate *priv;
305 obj = modest_mail_operation_new (op_type, source);
306 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
308 g_return_val_if_fail (error_handler != NULL, obj);
309 priv->error_checking = error_handler;
315 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
317 ModestMailOperationPrivate *priv;
319 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
320 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
322 if (priv->error_checking != NULL)
323 priv->error_checking (self, priv->error_checking_user_data);
327 ModestMailOperationTypeOperation
328 modest_mail_operation_get_type_operation (ModestMailOperation *self)
330 ModestMailOperationPrivate *priv;
332 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
334 return priv->op_type;
338 modest_mail_operation_is_mine (ModestMailOperation *self,
341 ModestMailOperationPrivate *priv;
343 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
344 if (priv->source == NULL) return FALSE;
346 return priv->source == me;
350 modest_mail_operation_get_source (ModestMailOperation *self)
352 ModestMailOperationPrivate *priv;
354 g_return_val_if_fail (self, NULL);
356 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
358 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
362 return g_object_ref (priv->source);
365 ModestMailOperationStatus
366 modest_mail_operation_get_status (ModestMailOperation *self)
368 ModestMailOperationPrivate *priv;
370 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
371 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
372 MODEST_MAIL_OPERATION_STATUS_INVALID);
374 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
376 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
377 return MODEST_MAIL_OPERATION_STATUS_INVALID;
384 modest_mail_operation_get_error (ModestMailOperation *self)
386 ModestMailOperationPrivate *priv;
388 g_return_val_if_fail (self, NULL);
389 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
391 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
394 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
402 modest_mail_operation_cancel (ModestMailOperation *self)
404 ModestMailOperationPrivate *priv;
406 if (!MODEST_IS_MAIL_OPERATION (self)) {
407 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
411 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
413 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
420 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
426 modest_mail_operation_get_task_done (ModestMailOperation *self)
428 ModestMailOperationPrivate *priv;
430 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
437 modest_mail_operation_get_task_total (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
448 modest_mail_operation_is_finished (ModestMailOperation *self)
450 ModestMailOperationPrivate *priv;
451 gboolean retval = FALSE;
453 if (!MODEST_IS_MAIL_OPERATION (self)) {
454 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
460 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
473 modest_mail_operation_get_id (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
484 modest_mail_operation_set_id (ModestMailOperation *self,
487 ModestMailOperationPrivate *priv;
489 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
496 * Creates an image of the current state of a mail operation, the
497 * caller must free it
499 static ModestMailOperationState *
500 modest_mail_operation_clone_state (ModestMailOperation *self)
502 ModestMailOperationState *state;
503 ModestMailOperationPrivate *priv;
505 /* FIXME: this should be fixed properly
507 * in some cases, priv was NULL, so checking here to
510 g_return_val_if_fail (self, NULL);
511 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
512 g_return_val_if_fail (priv, NULL);
517 state = g_slice_new (ModestMailOperationState);
519 state->status = priv->status;
520 state->op_type = priv->op_type;
521 state->done = priv->done;
522 state->total = priv->total;
523 state->finished = modest_mail_operation_is_finished (self);
524 state->bytes_done = 0;
525 state->bytes_total = 0;
530 /* ******************************************************************* */
531 /* ************************** SEND ACTIONS ************************* */
532 /* ******************************************************************* */
535 modest_mail_operation_send_mail (ModestMailOperation *self,
536 TnyTransportAccount *transport_account,
539 TnySendQueue *send_queue = NULL;
540 ModestMailOperationPrivate *priv;
542 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
543 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
544 g_return_if_fail (TNY_IS_MSG (msg));
546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
548 /* Get account and set it into mail_operation */
549 priv->account = g_object_ref (transport_account);
553 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
554 if (!TNY_IS_SEND_QUEUE(send_queue)) {
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
557 "modest: could not find send queue for account\n");
559 /* TODO: connect to the msg-sent in order to know when
560 the mail operation is finished */
561 tny_send_queue_add (send_queue, msg, &(priv->error));
562 /* TODO: we're setting always success, do the check in
564 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
567 /* TODO: do this in the handler of the "msg-sent"
568 signal.Notify about operation end */
569 modest_mail_operation_notify_end (self);
573 idle_create_msg_cb (gpointer idle_data)
575 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
577 gdk_threads_enter ();
578 info->callback (info->mail_op, info->msg, info->userdata);
579 gdk_threads_leave ();
580 g_object_unref (info->mail_op);
582 g_object_unref (info->msg);
583 g_slice_free (CreateMsgIdleInfo, info);
589 create_msg_thread (gpointer thread_data)
591 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
592 TnyMsg *new_msg = NULL;
593 ModestMailOperationPrivate *priv;
595 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
596 if (info->html_body == NULL) {
597 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
598 info->bcc, info->subject, info->plain_body,
599 info->attachments_list); /* FIXME: attachments */
601 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
602 info->bcc, info->subject, info->html_body,
603 info->plain_body, info->attachments_list);
608 /* Set priority flags in message */
609 header = tny_msg_get_header (new_msg);
610 if (info->priority_flags != 0)
611 tny_header_set_flags (header, info->priority_flags);
612 if (info->attachments_list != NULL) {
613 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
615 g_object_unref (G_OBJECT(header));
617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
620 "modest: failed to create a new msg\n");
628 g_free (info->plain_body);
629 g_free (info->html_body);
630 g_free (info->subject);
631 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
632 g_list_free (info->attachments_list);
634 if (info->callback) {
635 CreateMsgIdleInfo *idle_info;
636 idle_info = g_slice_new0 (CreateMsgIdleInfo);
637 idle_info->mail_op = info->mail_op;
638 g_object_ref (info->mail_op);
639 idle_info->msg = new_msg;
641 g_object_ref (new_msg);
642 idle_info->callback = info->callback;
643 idle_info->userdata = info->userdata;
644 g_idle_add (idle_create_msg_cb, idle_info);
646 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
649 g_object_unref (info->mail_op);
650 g_slice_free (CreateMsgInfo, info);
655 modest_mail_operation_create_msg (ModestMailOperation *self,
656 const gchar *from, const gchar *to,
657 const gchar *cc, const gchar *bcc,
658 const gchar *subject, const gchar *plain_body,
659 const gchar *html_body,
660 const GList *attachments_list,
661 TnyHeaderFlags priority_flags,
662 ModestMailOperationCreateMsgCallback callback,
665 CreateMsgInfo *info = NULL;
667 info = g_slice_new0 (CreateMsgInfo);
668 info->mail_op = self;
671 info->from = g_strdup (from);
672 info->to = g_strdup (to);
673 info->cc = g_strdup (cc);
674 info->subject = g_strdup (subject);
675 info->plain_body = g_strdup (plain_body);
676 info->html_body = g_strdup (html_body);
677 info->attachments_list = g_list_copy ((GList *) attachments_list);
678 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
679 info->priority_flags = priority_flags;
681 info->callback = callback;
682 info->userdata = userdata;
684 g_thread_create (create_msg_thread, info, FALSE, NULL);
689 TnyTransportAccount *transport_account;
694 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
698 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
706 /* Call mail operation */
707 modest_mail_operation_send_mail (self, info->transport_account, msg);
709 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
711 if (info->draft_msg != NULL) {
712 header = tny_msg_get_header (info->draft_msg);
713 /* Note: This can fail (with a warning) if the message is not really already in a folder,
714 * because this function requires it to have a UID. */
715 tny_folder_remove_msg (folder, header, NULL);
716 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
717 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
718 g_object_unref (header);
724 g_object_unref (info->draft_msg);
725 if (info->transport_account)
726 g_object_unref (info->transport_account);
727 g_slice_free (SendNewMailInfo, info);
728 modest_mail_operation_notify_end (self);
732 modest_mail_operation_send_new_mail (ModestMailOperation *self,
733 TnyTransportAccount *transport_account,
735 const gchar *from, const gchar *to,
736 const gchar *cc, const gchar *bcc,
737 const gchar *subject, const gchar *plain_body,
738 const gchar *html_body,
739 const GList *attachments_list,
740 TnyHeaderFlags priority_flags)
742 ModestMailOperationPrivate *priv = NULL;
743 SendNewMailInfo *info;
745 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
746 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
750 /* Check parametters */
752 /* Set status failed and set an error */
753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
755 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
756 _("Error trying to send a mail. You need to set at least one recipient"));
759 info = g_slice_new0 (SendNewMailInfo);
760 info->transport_account = transport_account;
761 if (transport_account)
762 g_object_ref (transport_account);
763 info->draft_msg = draft_msg;
765 g_object_ref (draft_msg);
766 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
767 attachments_list, priority_flags,
768 modest_mail_operation_send_new_mail_cb, info);
774 TnyTransportAccount *transport_account;
776 ModestMsgEditWindow *edit_window;
780 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
784 TnyFolder *folder = NULL;
785 TnyHeader *header = NULL;
786 ModestMailOperationPrivate *priv = NULL;
787 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
791 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
792 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
793 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
794 "modest: failed to create a new msg\n");
798 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
801 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
802 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
803 "modest: failed to create a new msg\n");
807 if (info->draft_msg != NULL) {
808 header = tny_msg_get_header (info->draft_msg);
809 /* Remove the old draft expunging it */
810 tny_folder_remove_msg (folder, header, NULL);
811 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
812 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
813 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
814 g_object_unref (header);
818 tny_folder_add_msg (folder, msg, &(priv->error));
821 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 if (info->edit_window)
826 modest_msg_edit_window_set_draft (info->edit_window, msg);
831 g_object_unref (G_OBJECT(folder));
832 if (info->edit_window)
833 g_object_unref (G_OBJECT(info->edit_window));
835 g_object_unref (G_OBJECT (info->draft_msg));
836 if (info->transport_account)
837 g_object_unref (G_OBJECT(info->transport_account));
838 g_slice_free (SaveToDraftsInfo, info);
840 modest_mail_operation_notify_end (self);
844 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
845 TnyTransportAccount *transport_account,
847 ModestMsgEditWindow *edit_window,
848 const gchar *from, const gchar *to,
849 const gchar *cc, const gchar *bcc,
850 const gchar *subject, const gchar *plain_body,
851 const gchar *html_body,
852 const GList *attachments_list,
853 TnyHeaderFlags priority_flags)
855 ModestMailOperationPrivate *priv = NULL;
856 SaveToDraftsInfo *info = NULL;
858 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
859 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
863 /* Get account and set it into mail_operation */
864 priv->account = g_object_ref (transport_account);
866 info = g_slice_new0 (SaveToDraftsInfo);
867 info->transport_account = g_object_ref (transport_account);
868 info->draft_msg = draft_msg;
870 g_object_ref (draft_msg);
871 info->edit_window = edit_window;
873 g_object_ref (edit_window);
875 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
876 attachments_list, priority_flags,
877 modest_mail_operation_save_to_drafts_cb, info);
883 ModestMailOperation *mail_op;
884 TnyStoreAccount *account;
885 TnyTransportAccount *transport_account;
888 gchar *retrieve_type;
890 UpdateAccountCallback callback;
897 ModestMailOperation *mail_op;
898 TnyMimePart *mime_part;
900 GetMimePartSizeCallback callback;
902 } GetMimePartSizeInfo;
904 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
905 /* We use this folder observer to track the headers that have been
906 * added to a folder */
909 TnyList *new_headers;
910 } InternalFolderObserver;
914 } InternalFolderObserverClass;
916 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
918 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
919 internal_folder_observer,
921 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
925 foreach_add_item (gpointer header, gpointer user_data)
927 tny_list_prepend (TNY_LIST (user_data),
928 g_object_ref (G_OBJECT (header)));
931 /* This is the method that looks for new messages in a folder */
933 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
935 InternalFolderObserver *derived = (InternalFolderObserver *)self;
937 TnyFolderChangeChanged changed;
939 changed = tny_folder_change_get_changed (change);
941 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
944 /* Get added headers */
945 list = tny_simple_list_new ();
946 tny_folder_change_get_added_headers (change, list);
948 /* Add them to the folder observer */
949 tny_list_foreach (list, foreach_add_item,
950 derived->new_headers);
952 g_object_unref (G_OBJECT (list));
957 internal_folder_observer_init (InternalFolderObserver *self)
959 self->new_headers = tny_simple_list_new ();
962 internal_folder_observer_finalize (GObject *object)
964 InternalFolderObserver *self;
966 self = (InternalFolderObserver *) object;
967 g_object_unref (self->new_headers);
969 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
972 tny_folder_observer_init (TnyFolderObserverIface *iface)
974 iface->update_func = internal_folder_observer_update;
977 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
979 GObjectClass *object_class;
981 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
982 object_class = (GObjectClass*) klass;
983 object_class->finalize = internal_folder_observer_finalize;
989 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
992 TnyList *folders = tny_simple_list_new ();
994 tny_folder_store_get_folders (store, folders, query, NULL);
995 iter = tny_list_create_iterator (folders);
997 while (!tny_iterator_is_done (iter)) {
999 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1001 tny_list_prepend (all_folders, G_OBJECT (folder));
1002 recurse_folders (folder, query, all_folders);
1003 g_object_unref (G_OBJECT (folder));
1005 tny_iterator_next (iter);
1007 g_object_unref (G_OBJECT (iter));
1008 g_object_unref (G_OBJECT (folders));
1012 * Issues the "progress-changed" signal. The timer won't be removed,
1013 * so you must call g_source_remove to stop the signal emission
1016 idle_notify_progress (gpointer data)
1018 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1019 ModestMailOperationState *state;
1021 state = modest_mail_operation_clone_state (mail_op);
1022 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1023 gdk_threads_enter ();
1025 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1026 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1027 gdk_threads_leave ();
1029 g_slice_free (ModestMailOperationState, state);
1035 * Issues the "progress-changed" signal and removes the timer. It uses
1036 * a lock to ensure that the progress information of the mail
1037 * operation is not modified while there are notifications pending
1040 idle_notify_progress_once (gpointer data)
1044 pair = (ModestPair *) data;
1046 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1047 gdk_threads_enter ();
1049 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_leave ();
1054 /* Free the state and the reference to the mail operation */
1055 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1056 g_object_unref (pair->first);
1062 * Used to notify the queue from the main
1063 * loop. We call it inside an idle call to achieve that
1066 idle_notify_queue (gpointer data)
1068 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1070 /* Do not need to block, the notify end will do it for us */
1071 modest_mail_operation_notify_end (mail_op);
1072 g_object_unref (mail_op);
1078 compare_headers_by_date (gconstpointer a,
1081 TnyHeader **header1, **header2;
1082 time_t sent1, sent2;
1084 header1 = (TnyHeader **) a;
1085 header2 = (TnyHeader **) b;
1087 sent1 = tny_header_get_date_sent (*header1);
1088 sent2 = tny_header_get_date_sent (*header2);
1090 /* We want the most recent ones (greater time_t) at the
1099 set_last_updated_idle (gpointer data)
1101 gdk_threads_enter ();
1103 /* It does not matter if the time is not exactly the same than
1104 the time when this idle was called, it's just an
1105 approximation and it won't be very different */
1106 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1108 MODEST_ACCOUNT_LAST_UPDATED,
1112 gdk_threads_leave ();
1118 idle_update_account_cb (gpointer data)
1120 UpdateAccountInfo *idle_info;
1122 idle_info = (UpdateAccountInfo *) data;
1124 gdk_threads_enter ();
1125 idle_info->callback (idle_info->mail_op,
1126 idle_info->new_headers,
1127 idle_info->user_data);
1128 gdk_threads_leave ();
1131 g_object_unref (idle_info->mail_op);
1139 update_account_thread (gpointer thr_user_data)
1141 static gboolean first_time = TRUE;
1142 UpdateAccountInfo *info;
1143 TnyList *all_folders = NULL;
1144 GPtrArray *new_headers = NULL;
1145 TnyIterator *iter = NULL;
1146 TnyFolderStoreQuery *query = NULL;
1147 ModestMailOperationPrivate *priv = NULL;
1148 ModestTnySendQueue *send_queue = NULL;
1150 info = (UpdateAccountInfo *) thr_user_data;
1151 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1153 /* Get account and set it into mail_operation */
1154 priv->account = g_object_ref (info->account);
1157 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1158 * show any updates unless we do that
1160 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1161 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1163 /* Get all the folders. We can do it synchronously because
1164 we're already running in a different thread than the UI */
1165 all_folders = tny_simple_list_new ();
1166 query = tny_folder_store_query_new ();
1167 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1168 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1173 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1177 iter = tny_list_create_iterator (all_folders);
1178 while (!tny_iterator_is_done (iter)) {
1179 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1181 recurse_folders (folder, query, all_folders);
1182 tny_iterator_next (iter);
1184 g_object_unref (G_OBJECT (iter));
1186 /* Update status and notify. We need to call the notification
1187 with a source function in order to call it from the main
1188 loop. We need that in order not to get into trouble with
1189 Gtk+. We use a timeout in order to provide more status
1190 information, because the sync tinymail call does not
1191 provide it for the moment */
1192 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1194 /* Refresh folders */
1195 new_headers = g_ptr_array_new ();
1196 iter = tny_list_create_iterator (all_folders);
1198 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
1200 InternalFolderObserver *observer;
1201 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1203 /* Refresh the folder */
1204 /* Our observer receives notification of new emails during folder refreshes,
1205 * so we can use observer->new_headers.
1207 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1208 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1210 /* This gets the status information (headers) from the server.
1211 * We use the blocking version, because we are already in a separate
1215 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1216 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1219 /* If the retrieve type is full messages, refresh and get the messages */
1220 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1222 iter = tny_list_create_iterator (observer->new_headers);
1223 while (!tny_iterator_is_done (iter)) {
1224 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1226 /* Apply per-message size limits */
1227 if (tny_header_get_message_size (header) < info->max_size)
1228 g_ptr_array_add (new_headers, g_object_ref (header));
1230 g_object_unref (header);
1231 tny_iterator_next (iter);
1233 g_object_unref (iter);
1235 /* We do not need to do it the first time
1236 because it's automatically done by the tree
1238 if (G_UNLIKELY (!first_time))
1239 tny_folder_poke_status (TNY_FOLDER (folder));
1241 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1242 g_object_unref (observer);
1245 g_object_unref (G_OBJECT (folder));
1248 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1252 tny_iterator_next (iter);
1255 did_a_cancel = FALSE;
1257 g_object_unref (G_OBJECT (iter));
1258 g_source_remove (timeout);
1260 if (new_headers->len > 0) {
1264 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1266 /* Apply message count limit */
1267 /* If the number of messages exceeds the maximum, ask the
1268 * user to download them all,
1269 * as per the UI spec "Retrieval Limits" section in 4.4:
1271 if (new_headers->len > info->retrieve_limit) {
1272 /* TODO: Ask the user, instead of just
1274 * mail_nc_msg_count_limit_exceeded, with 'Get
1275 * all' and 'Newest only' buttons. */
1276 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1277 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1278 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1279 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1280 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1285 priv->total = MIN (new_headers->len, info->retrieve_limit);
1286 while (msg_num < priv->total) {
1288 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1289 TnyFolder *folder = tny_header_get_folder (header);
1290 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1291 ModestMailOperationState *state;
1295 /* We can not just use the mail operation because the
1296 values of done and total could change before the
1298 state = modest_mail_operation_clone_state (info->mail_op);
1299 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1300 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1301 pair, (GDestroyNotify) modest_pair_free);
1303 g_object_unref (msg);
1304 g_object_unref (folder);
1308 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1309 g_ptr_array_free (new_headers, FALSE);
1312 /* Perform send (if operation was not cancelled) */
1313 if (did_a_cancel) goto out;
1314 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1317 if (priv->account != NULL)
1318 g_object_unref (priv->account);
1319 priv->account = g_object_ref (info->transport_account);
1321 send_queue = modest_runtime_get_send_queue (info->transport_account);
1323 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1324 modest_tny_send_queue_try_to_send (send_queue);
1325 /* g_source_remove (timeout); */
1327 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1328 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1329 "cannot create a send queue for %s\n",
1330 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1331 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1334 /* Check if the operation was a success */
1336 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1338 /* Update the last updated key */
1339 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1340 set_last_updated_idle,
1341 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1342 (GDestroyNotify) g_free);
1347 if (info->callback) {
1348 UpdateAccountInfo *idle_info;
1350 /* This thread is not in the main lock */
1351 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1352 idle_info->mail_op = g_object_ref (info->mail_op);
1353 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1354 idle_info->callback = info->callback;
1355 g_idle_add (idle_update_account_cb, idle_info);
1358 /* Notify about operation end. Note that the info could be
1359 freed before this idle happens, but the mail operation will
1361 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1364 g_object_unref (query);
1365 g_object_unref (all_folders);
1366 g_object_unref (info->account);
1367 g_object_unref (info->transport_account);
1368 g_free (info->retrieve_type);
1369 g_slice_free (UpdateAccountInfo, info);
1377 modest_mail_operation_update_account (ModestMailOperation *self,
1378 const gchar *account_name,
1379 UpdateAccountCallback callback,
1382 GThread *thread = NULL;
1383 UpdateAccountInfo *info = NULL;
1384 ModestMailOperationPrivate *priv = NULL;
1385 ModestAccountMgr *mgr = NULL;
1386 TnyStoreAccount *store_account = NULL;
1387 TnyTransportAccount *transport_account = NULL;
1389 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1390 g_return_val_if_fail (account_name, FALSE);
1392 /* Init mail operation. Set total and done to 0, and do not
1393 update them, this way the progress objects will know that
1394 we have no clue about the number of the objects */
1395 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1398 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1400 /* Get the Modest account */
1401 store_account = (TnyStoreAccount *)
1402 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1404 TNY_ACCOUNT_TYPE_STORE);
1406 /* Make sure that we have a connection, and request one
1408 * TODO: Is there some way to trigger this for every attempt to
1409 * use the network? */
1410 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1413 if (!store_account) {
1414 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1415 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1416 "cannot get tny store account for %s\n", account_name);
1421 /* Get the transport account, we can not do it in the thread
1422 due to some problems with dbus */
1423 transport_account = (TnyTransportAccount *)
1424 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1426 if (!transport_account) {
1427 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1428 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1429 "cannot get tny transport account for %s\n", account_name);
1433 /* Create the helper object */
1434 info = g_slice_new (UpdateAccountInfo);
1435 info->mail_op = self;
1436 info->account = store_account;
1437 info->transport_account = transport_account;
1438 info->callback = callback;
1439 info->user_data = user_data;
1441 /* Get the message size limit */
1442 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1443 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1444 if (info->max_size == 0)
1445 info->max_size = G_MAXINT;
1447 info->max_size = info->max_size * KB;
1449 /* Get per-account retrieval type */
1450 mgr = modest_runtime_get_account_mgr ();
1451 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1452 MODEST_ACCOUNT_RETRIEVE, FALSE);
1454 /* Get per-account message amount retrieval limit */
1455 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1456 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1457 if (info->retrieve_limit == 0)
1458 info->retrieve_limit = G_MAXINT;
1460 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1462 /* Set account busy */
1463 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1464 priv->account_name = g_strdup(account_name);
1466 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1471 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1473 callback (self, 0, user_data);
1474 modest_mail_operation_notify_end (self);
1478 /* ******************************************************************* */
1479 /* ************************** STORE ACTIONS ************************* */
1480 /* ******************************************************************* */
1484 modest_mail_operation_create_folder (ModestMailOperation *self,
1485 TnyFolderStore *parent,
1488 ModestMailOperationPrivate *priv;
1489 TnyFolder *new_folder = NULL;
1491 TnyList *list = tny_simple_list_new ();
1492 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1494 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1495 g_return_val_if_fail (name, NULL);
1497 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1499 /* Check for already existing folder */
1500 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1501 tny_folder_store_get_folders (parent, list, query, NULL);
1502 g_object_unref (G_OBJECT (query));
1504 if (tny_list_get_length (list) > 0) {
1505 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1506 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1507 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1508 _CS("ckdg_ib_folder_already_exists"));
1511 g_object_unref (G_OBJECT (list));
1514 if (TNY_IS_FOLDER (parent)) {
1515 /* Check folder rules */
1516 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1517 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1518 /* Set status failed and set an error */
1519 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1520 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1521 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1522 _("mail_in_ui_folder_create_error"));
1526 if (!strcmp (name, " ") || strchr (name, '/')) {
1527 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1528 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1529 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1530 _("mail_in_ui_folder_create_error"));
1534 /* Create the folder */
1535 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1536 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1538 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1541 /* Notify about operation end */
1542 modest_mail_operation_notify_end (self);
1548 modest_mail_operation_remove_folder (ModestMailOperation *self,
1550 gboolean remove_to_trash)
1552 TnyAccount *account;
1553 ModestMailOperationPrivate *priv;
1554 ModestTnyFolderRules rules;
1556 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1557 g_return_if_fail (TNY_IS_FOLDER (folder));
1559 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1561 /* Check folder rules */
1562 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1563 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1564 /* Set status failed and set an error */
1565 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1566 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1567 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1568 _("mail_in_ui_folder_delete_error"));
1572 /* Get the account */
1573 account = modest_tny_folder_get_account (folder);
1574 priv->account = g_object_ref(account);
1576 /* Delete folder or move to trash */
1577 if (remove_to_trash) {
1578 TnyFolder *trash_folder = NULL;
1579 trash_folder = modest_tny_account_get_special_folder (account,
1580 TNY_FOLDER_TYPE_TRASH);
1581 /* TODO: error_handling */
1582 modest_mail_operation_xfer_folder (self, folder,
1583 TNY_FOLDER_STORE (trash_folder),
1586 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1588 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1589 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1592 g_object_unref (G_OBJECT (parent));
1594 g_object_unref (G_OBJECT (account));
1597 /* Notify about operation end */
1598 modest_mail_operation_notify_end (self);
1602 transfer_folder_status_cb (GObject *obj,
1606 ModestMailOperation *self;
1607 ModestMailOperationPrivate *priv;
1608 ModestMailOperationState *state;
1609 XFerMsgAsyncHelper *helper;
1611 g_return_if_fail (status != NULL);
1612 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1614 helper = (XFerMsgAsyncHelper *) user_data;
1615 g_return_if_fail (helper != NULL);
1617 self = helper->mail_op;
1618 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1620 priv->done = status->position;
1621 priv->total = status->of_total;
1623 state = modest_mail_operation_clone_state (self);
1624 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1625 gdk_threads_enter ();
1627 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1628 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1629 gdk_threads_leave ();
1631 g_slice_free (ModestMailOperationState, state);
1636 transfer_folder_cb (TnyFolder *folder,
1637 TnyFolderStore *into,
1639 TnyFolder *new_folder,
1643 XFerMsgAsyncHelper *helper;
1644 ModestMailOperation *self = NULL;
1645 ModestMailOperationPrivate *priv = NULL;
1647 helper = (XFerMsgAsyncHelper *) user_data;
1648 g_return_if_fail (helper != NULL);
1650 self = helper->mail_op;
1651 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1654 priv->error = g_error_copy (*err);
1656 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1657 } else if (cancelled) {
1658 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1659 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1660 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1661 _("Transference of %s was cancelled."),
1662 tny_folder_get_name (folder));
1665 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1668 /* Notify about operation end */
1669 modest_mail_operation_notify_end (self);
1671 /* If user defined callback function was defined, call it */
1672 if (helper->user_callback) {
1673 gdk_threads_enter ();
1674 helper->user_callback (priv->source, helper->user_data);
1675 gdk_threads_leave ();
1679 g_object_unref (helper->mail_op);
1680 g_slice_free (XFerMsgAsyncHelper, helper);
1685 * This function checks if the new name is a valid name for our local
1686 * folders account. The new name could not be the same than then name
1687 * of any of the mandatory local folders
1689 * We can not rely on tinymail because tinymail does not check the
1690 * name of the virtual folders that the account could have in the case
1691 * that we're doing a rename (because it directly calls Camel which
1692 * knows nothing about our virtual folders).
1694 * In the case of an actual copy/move (i.e. move/copy a folder between
1695 * accounts) tinymail uses the tny_folder_store_create_account which
1696 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1697 * checks the new name of the folder, so this call in that case
1698 * wouldn't be needed. *But* NOTE that if tinymail changes its
1699 * implementation (if folder transfers within the same account is no
1700 * longer implemented as a rename) this call will allow Modest to work
1703 * If the new name is not valid, this function will set the status to
1704 * failed and will set also an error in the mail operation
1707 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1708 TnyFolderStore *into,
1709 const gchar *new_name)
1711 if (TNY_IS_ACCOUNT (into) &&
1712 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1713 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1715 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1716 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1717 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1718 _("FIXME: folder name already in use"));
1725 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1727 TnyFolderStore *parent,
1728 gboolean delete_original,
1729 XferMsgsAsynUserCallback user_callback,
1732 ModestMailOperationPrivate *priv = NULL;
1733 ModestTnyFolderRules parent_rules = 0, rules;
1734 XFerMsgAsyncHelper *helper = NULL;
1736 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1737 g_return_if_fail (TNY_IS_FOLDER (folder));
1739 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1741 /* Get account and set it into mail_operation */
1742 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1743 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1745 /* Get folder rules */
1746 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1747 if (TNY_IS_FOLDER (parent))
1748 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1750 /* The moveable restriction is applied also to copy operation */
1751 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1752 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1753 /* Set status failed and set an error */
1754 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1756 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1757 _("mail_in_ui_folder_move_target_error"));
1759 /* Notify the queue */
1760 modest_mail_operation_notify_end (self);
1761 } else if (TNY_IS_FOLDER (parent) &&
1762 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1763 /* Set status failed and set an error */
1764 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1765 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1766 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1767 _("FIXME: parent folder does not accept new folders"));
1769 /* Notify the queue */
1770 modest_mail_operation_notify_end (self);
1774 /* Check that the new folder name is not used by any
1775 special local folder */
1776 if (new_name_valid_if_local_account (priv, parent,
1777 tny_folder_get_name (folder))) {
1778 /* Create the helper */
1779 helper = g_slice_new0 (XFerMsgAsyncHelper);
1780 helper->mail_op = g_object_ref(self);
1781 helper->dest_folder = NULL;
1782 helper->headers = NULL;
1783 helper->user_callback = user_callback;
1784 helper->user_data = user_data;
1786 /* Move/Copy folder */
1787 tny_folder_copy_async (folder,
1789 tny_folder_get_name (folder),
1792 transfer_folder_status_cb,
1795 modest_mail_operation_notify_end (self);
1801 modest_mail_operation_rename_folder (ModestMailOperation *self,
1805 ModestMailOperationPrivate *priv;
1806 ModestTnyFolderRules rules;
1807 XFerMsgAsyncHelper *helper;
1809 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1810 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1811 g_return_if_fail (name);
1813 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1815 /* Get account and set it into mail_operation */
1816 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1818 /* Check folder rules */
1819 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1820 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1821 /* Set status failed and set an error */
1822 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1823 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1824 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1825 _("FIXME: unable to rename"));
1827 /* Notify about operation end */
1828 modest_mail_operation_notify_end (self);
1829 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1830 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1831 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1832 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1833 _("FIXME: unable to rename"));
1834 /* Notify about operation end */
1835 modest_mail_operation_notify_end (self);
1837 TnyFolderStore *into;
1839 into = tny_folder_get_folder_store (folder);
1841 /* Check that the new folder name is not used by any
1842 special local folder */
1843 if (new_name_valid_if_local_account (priv, into, name)) {
1844 /* Create the helper */
1845 helper = g_slice_new0 (XFerMsgAsyncHelper);
1846 helper->mail_op = g_object_ref(self);
1847 helper->dest_folder = NULL;
1848 helper->headers = NULL;
1849 helper->user_callback = NULL;
1850 helper->user_data = NULL;
1852 /* Rename. Camel handles folder subscription/unsubscription */
1853 tny_folder_copy_async (folder, into, name, TRUE,
1855 transfer_folder_status_cb,
1858 modest_mail_operation_notify_end (self);
1860 g_object_unref (into);
1864 /* ******************************************************************* */
1865 /* ************************** MSG ACTIONS ************************* */
1866 /* ******************************************************************* */
1868 void modest_mail_operation_get_msg (ModestMailOperation *self,
1870 GetMsgAsyncUserCallback user_callback,
1873 GetMsgAsyncHelper *helper = NULL;
1875 ModestMailOperationPrivate *priv;
1877 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1878 g_return_if_fail (TNY_IS_HEADER (header));
1880 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1881 folder = tny_header_get_folder (header);
1883 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1885 /* Get message from folder */
1887 /* Get account and set it into mail_operation */
1888 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1890 helper = g_slice_new0 (GetMsgAsyncHelper);
1891 helper->mail_op = self;
1892 helper->user_callback = user_callback;
1893 helper->user_data = user_data;
1894 helper->header = g_object_ref (header);
1896 // The callback's reference so that the mail op is not
1897 // finalized until the async operation is completed even if
1898 // the user canceled the request meanwhile.
1899 g_object_ref (G_OBJECT (helper->mail_op));
1901 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1903 g_object_unref (G_OBJECT (folder));
1905 /* Set status failed and set an error */
1906 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1907 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1908 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1909 _("Error trying to get a message. No folder found for header"));
1911 /* Notify the queue */
1912 modest_mail_operation_notify_end (self);
1917 idle_get_mime_part_size_cb (gpointer userdata)
1919 GetMimePartSizeInfo *idle_info;
1921 idle_info = (GetMimePartSizeInfo *) userdata;
1923 gdk_threads_enter ();
1924 idle_info->callback (idle_info->mail_op,
1926 idle_info->userdata);
1927 gdk_threads_leave ();
1929 g_object_unref (idle_info->mail_op);
1930 g_slice_free (GetMimePartSizeInfo, idle_info);
1936 get_mime_part_size_thread (gpointer thr_user_data)
1938 GetMimePartSizeInfo *info;
1939 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1943 ModestMailOperationPrivate *priv;
1945 info = (GetMimePartSizeInfo *) thr_user_data;
1946 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1948 stream = tny_camel_mem_stream_new ();
1949 tny_mime_part_decode_to_stream (info->mime_part, stream);
1950 tny_stream_reset (stream);
1951 if (tny_stream_is_eos (stream)) {
1952 tny_stream_close (stream);
1953 stream = tny_mime_part_get_stream (info->mime_part);
1956 while (!tny_stream_is_eos (stream)) {
1957 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1958 total += readed_size;
1961 if (info->callback) {
1962 GetMimePartSizeInfo *idle_info;
1964 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1965 idle_info->mail_op = g_object_ref (info->mail_op);
1966 idle_info->size = total;
1967 idle_info->callback = info->callback;
1968 idle_info->userdata = info->userdata;
1969 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1972 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1974 g_object_unref (info->mail_op);
1975 g_object_unref (stream);
1976 g_object_unref (info->mime_part);
1977 g_slice_free (GetMimePartSizeInfo, info);
1983 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1985 GetMimePartSizeCallback user_callback,
1987 GDestroyNotify notify)
1989 GetMimePartSizeInfo *info;
1990 ModestMailOperationPrivate *priv;
1993 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1994 g_return_if_fail (TNY_IS_MIME_PART (part));
1996 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1998 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1999 info = g_slice_new0 (GetMimePartSizeInfo);
2000 info->mail_op = g_object_ref (self);
2001 info->mime_part = g_object_ref (part);
2002 info->callback = user_callback;
2003 info->userdata = user_data;
2005 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2010 get_msg_cb (TnyFolder *folder,
2016 GetMsgAsyncHelper *helper = NULL;
2017 ModestMailOperation *self = NULL;
2018 ModestMailOperationPrivate *priv = NULL;
2020 helper = (GetMsgAsyncHelper *) user_data;
2021 g_return_if_fail (helper != NULL);
2022 self = helper->mail_op;
2023 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2024 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2026 /* Check errors and cancel */
2028 priv->error = g_error_copy (*error);
2029 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2030 } else if (cancelled) {
2031 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2032 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2033 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2034 _("Error trying to refresh the contents of %s"),
2035 tny_folder_get_name (folder));
2037 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2040 /* If user defined callback function was defined, call it even
2041 if the operation failed*/
2042 if (helper->user_callback) {
2043 /* This callback is called into an iddle by tinymail,
2044 and idles are not in the main lock */
2045 gdk_threads_enter ();
2046 helper->user_callback (self, helper->header, msg, helper->user_data);
2047 gdk_threads_leave ();
2050 /* Notify about operation end */
2051 modest_mail_operation_notify_end (self);
2053 g_object_unref (helper->mail_op);
2054 g_object_unref (helper->header);
2055 g_slice_free (GetMsgAsyncHelper, helper);
2060 get_msg_status_cb (GObject *obj,
2064 GetMsgAsyncHelper *helper = NULL;
2065 ModestMailOperation *self;
2066 ModestMailOperationPrivate *priv;
2067 ModestMailOperationState *state;
2069 g_return_if_fail (status != NULL);
2070 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2072 helper = (GetMsgAsyncHelper *) user_data;
2073 g_return_if_fail (helper != NULL);
2075 self = helper->mail_op;
2076 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2078 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2079 TnyFolder *folder = tny_header_get_folder (helper->header);
2081 TnyAccount *account;
2082 account = tny_folder_get_account (folder);
2084 tny_account_cancel (account);
2085 g_object_unref (account);
2087 g_object_unref (folder);
2096 state = modest_mail_operation_clone_state (self);
2097 state->bytes_done = status->position;
2098 state->bytes_total = status->of_total;
2099 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2100 gdk_threads_enter ();
2102 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2103 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2104 gdk_threads_leave ();
2106 g_slice_free (ModestMailOperationState, state);
2109 /****************************************************/
2111 ModestMailOperation *mail_op;
2113 GetMsgAsyncUserCallback user_callback;
2115 GDestroyNotify notify;
2119 GetMsgAsyncUserCallback user_callback;
2123 ModestMailOperation *mail_op;
2124 } NotifyGetMsgsInfo;
2128 * Used by get_msgs_full_thread to call the user_callback for each
2129 * message that has been read
2132 notify_get_msgs_full (gpointer data)
2134 NotifyGetMsgsInfo *info;
2136 info = (NotifyGetMsgsInfo *) data;
2138 /* Call the user callback. Idles are not in the main lock, so
2140 gdk_threads_enter ();
2141 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2142 gdk_threads_leave ();
2144 g_slice_free (NotifyGetMsgsInfo, info);
2150 * Used by get_msgs_full_thread to free al the thread resources and to
2151 * call the destroy function for the passed user_data
2154 get_msgs_full_destroyer (gpointer data)
2156 GetFullMsgsInfo *info;
2158 info = (GetFullMsgsInfo *) data;
2161 gdk_threads_enter ();
2162 info->notify (info->user_data);
2163 gdk_threads_leave ();
2167 g_object_unref (info->headers);
2168 g_slice_free (GetFullMsgsInfo, info);
2174 get_msgs_full_thread (gpointer thr_user_data)
2176 GetFullMsgsInfo *info;
2177 ModestMailOperationPrivate *priv = NULL;
2178 TnyIterator *iter = NULL;
2180 info = (GetFullMsgsInfo *) thr_user_data;
2181 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2183 iter = tny_list_create_iterator (info->headers);
2184 while (!tny_iterator_is_done (iter)) {
2188 header = TNY_HEADER (tny_iterator_get_current (iter));
2189 folder = tny_header_get_folder (header);
2191 /* Get message from folder */
2194 /* The callback will call it per each header */
2195 msg = tny_folder_get_msg (folder, header, &(priv->error));
2198 ModestMailOperationState *state;
2203 /* notify progress */
2204 state = modest_mail_operation_clone_state (info->mail_op);
2205 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2206 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2207 pair, (GDestroyNotify) modest_pair_free);
2209 /* The callback is the responsible for
2210 freeing the message */
2211 if (info->user_callback) {
2212 NotifyGetMsgsInfo *info_notify;
2213 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2214 info_notify->user_callback = info->user_callback;
2215 info_notify->mail_op = info->mail_op;
2216 info_notify->header = g_object_ref (header);
2217 info_notify->msg = g_object_ref (msg);
2218 info_notify->user_data = info->user_data;
2219 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2220 notify_get_msgs_full,
2223 g_object_unref (msg);
2226 /* Set status failed and set an error */
2227 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2229 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2230 "Error trying to get a message. No folder found for header");
2232 g_object_unref (header);
2233 tny_iterator_next (iter);
2236 /* Set operation status */
2237 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2238 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2240 /* Notify about operation end */
2241 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2243 /* Free thread resources. Will be called after all previous idles */
2244 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2250 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2251 TnyList *header_list,
2252 GetMsgAsyncUserCallback user_callback,
2254 GDestroyNotify notify)
2256 TnyHeader *header = NULL;
2257 TnyFolder *folder = NULL;
2259 ModestMailOperationPrivate *priv = NULL;
2260 GetFullMsgsInfo *info = NULL;
2261 gboolean size_ok = TRUE;
2263 TnyIterator *iter = NULL;
2265 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2267 /* Init mail operation */
2268 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2269 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2271 priv->total = tny_list_get_length(header_list);
2273 /* Get account and set it into mail_operation */
2274 if (tny_list_get_length (header_list) >= 1) {
2275 iter = tny_list_create_iterator (header_list);
2276 header = TNY_HEADER (tny_iterator_get_current (iter));
2277 folder = tny_header_get_folder (header);
2278 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2279 g_object_unref (header);
2280 g_object_unref (folder);
2282 if (tny_list_get_length (header_list) == 1) {
2283 g_object_unref (iter);
2288 /* Get msg size limit */
2289 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2290 MODEST_CONF_MSG_SIZE_LIMIT,
2293 g_clear_error (&(priv->error));
2294 max_size = G_MAXINT;
2296 max_size = max_size * KB;
2299 /* Check message size limits. If there is only one message
2300 always retrieve it */
2302 while (!tny_iterator_is_done (iter) && size_ok) {
2303 header = TNY_HEADER (tny_iterator_get_current (iter));
2304 if (tny_header_get_message_size (header) >= max_size)
2306 g_object_unref (header);
2307 tny_iterator_next (iter);
2309 g_object_unref (iter);
2313 /* Create the info */
2314 info = g_slice_new0 (GetFullMsgsInfo);
2315 info->mail_op = self;
2316 info->user_callback = user_callback;
2317 info->user_data = user_data;
2318 info->headers = g_object_ref (header_list);
2319 info->notify = notify;
2321 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2323 /* Set status failed and set an error */
2324 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2325 /* FIXME: the error msg is different for pop */
2326 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2327 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2328 _("emev_ni_ui_imap_msg_size_exceed_error"));
2329 /* Remove from queue and free resources */
2330 modest_mail_operation_notify_end (self);
2338 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2339 gboolean remove_to_trash /*ignored*/)
2342 ModestMailOperationPrivate *priv;
2344 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2345 g_return_if_fail (TNY_IS_HEADER (header));
2347 if (remove_to_trash)
2348 g_warning ("remove to trash is not implemented");
2350 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2351 folder = tny_header_get_folder (header);
2353 /* Get account and set it into mail_operation */
2354 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2356 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2359 tny_folder_remove_msg (folder, header, &(priv->error));
2361 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2362 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2364 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2365 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2366 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2367 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2370 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2376 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2378 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2381 g_object_unref (G_OBJECT (folder));
2383 /* Notify about operation end */
2384 modest_mail_operation_notify_end (self);
2388 transfer_msgs_status_cb (GObject *obj,
2392 XFerMsgAsyncHelper *helper = NULL;
2393 ModestMailOperation *self;
2394 ModestMailOperationPrivate *priv;
2395 ModestMailOperationState *state;
2398 g_return_if_fail (status != NULL);
2399 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2401 helper = (XFerMsgAsyncHelper *) user_data;
2402 g_return_if_fail (helper != NULL);
2404 self = helper->mail_op;
2405 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2407 priv->done = status->position;
2408 priv->total = status->of_total;
2410 state = modest_mail_operation_clone_state (self);
2411 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2412 gdk_threads_enter ();
2414 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2415 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2416 gdk_threads_leave ();
2418 g_slice_free (ModestMailOperationState, state);
2423 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2425 XFerMsgAsyncHelper *helper;
2426 ModestMailOperation *self;
2427 ModestMailOperationPrivate *priv;
2429 helper = (XFerMsgAsyncHelper *) user_data;
2430 self = helper->mail_op;
2432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2435 priv->error = g_error_copy (*err);
2437 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2438 } else if (cancelled) {
2439 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2440 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2441 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2442 _("Error trying to refresh the contents of %s"),
2443 tny_folder_get_name (folder));
2446 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2449 /* Notify about operation end */
2450 modest_mail_operation_notify_end (self);
2452 /* If user defined callback function was defined, call it */
2453 if (helper->user_callback) {
2454 gdk_threads_enter ();
2455 helper->user_callback (priv->source, helper->user_data);
2456 gdk_threads_leave ();
2460 g_object_unref (helper->headers);
2461 g_object_unref (helper->dest_folder);
2462 g_object_unref (helper->mail_op);
2463 g_slice_free (XFerMsgAsyncHelper, helper);
2464 g_object_unref (folder);
2469 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2472 gboolean delete_original,
2473 XferMsgsAsynUserCallback user_callback,
2476 ModestMailOperationPrivate *priv;
2478 TnyFolder *src_folder;
2479 XFerMsgAsyncHelper *helper;
2481 ModestTnyFolderRules rules;
2482 const gchar *id1 = NULL;
2483 const gchar *id2 = NULL;
2484 gboolean same_folder = FALSE;
2486 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2487 g_return_if_fail (TNY_IS_LIST (headers));
2488 g_return_if_fail (TNY_IS_FOLDER (folder));
2490 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2493 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2495 /* Apply folder rules */
2496 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2497 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2498 /* Set status failed and set an error */
2499 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2500 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2501 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2502 _CS("ckct_ib_unable_to_paste_here"));
2503 /* Notify the queue */
2504 modest_mail_operation_notify_end (self);
2508 /* Get source folder */
2509 iter = tny_list_create_iterator (headers);
2510 header = TNY_HEADER (tny_iterator_get_current (iter));
2511 src_folder = tny_header_get_folder (header);
2512 g_object_unref (header);
2513 g_object_unref (iter);
2515 /* Check folder source and destination */
2516 id1 = tny_folder_get_id (src_folder);
2517 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2518 same_folder = !g_ascii_strcasecmp (id1, id2);
2520 /* Set status failed and set an error */
2521 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2522 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2523 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2524 _("mcen_ib_unable_to_copy_samefolder"));
2526 /* Notify the queue */
2527 modest_mail_operation_notify_end (self);
2530 g_object_unref (src_folder);
2534 /* Create the helper */
2535 helper = g_slice_new0 (XFerMsgAsyncHelper);
2536 helper->mail_op = g_object_ref(self);
2537 helper->dest_folder = g_object_ref(folder);
2538 helper->headers = g_object_ref(headers);
2539 helper->user_callback = user_callback;
2540 helper->user_data = user_data;
2542 /* Get account and set it into mail_operation */
2543 priv->account = modest_tny_folder_get_account (src_folder);
2545 /* Transfer messages */
2546 tny_folder_transfer_msgs_async (src_folder,
2551 transfer_msgs_status_cb,
2557 on_refresh_folder (TnyFolder *folder,
2562 RefreshAsyncHelper *helper = NULL;
2563 ModestMailOperation *self = NULL;
2564 ModestMailOperationPrivate *priv = NULL;
2566 helper = (RefreshAsyncHelper *) user_data;
2567 self = helper->mail_op;
2568 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2571 priv->error = g_error_copy (*error);
2572 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2577 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2578 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2579 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2580 _("Error trying to refresh the contents of %s"),
2581 tny_folder_get_name (folder));
2585 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2587 /* Call user defined callback, if it exists */
2588 if (helper->user_callback) {
2589 gdk_threads_enter ();
2590 helper->user_callback (self, folder, helper->user_data);
2591 gdk_threads_leave ();
2595 g_object_unref (helper->mail_op);
2596 g_slice_free (RefreshAsyncHelper, helper);
2598 /* Notify about operation end */
2599 modest_mail_operation_notify_end (self);
2603 on_refresh_folder_status_update (GObject *obj,
2607 RefreshAsyncHelper *helper = NULL;
2608 ModestMailOperation *self = NULL;
2609 ModestMailOperationPrivate *priv = NULL;
2610 ModestMailOperationState *state;
2612 g_return_if_fail (user_data != NULL);
2613 g_return_if_fail (status != NULL);
2614 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2616 helper = (RefreshAsyncHelper *) user_data;
2617 self = helper->mail_op;
2618 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2620 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2622 priv->done = status->position;
2623 priv->total = status->of_total;
2625 state = modest_mail_operation_clone_state (self);
2626 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2627 gdk_threads_enter ();
2629 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2630 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2631 gdk_threads_leave ();
2633 g_slice_free (ModestMailOperationState, state);
2637 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2639 RefreshAsyncUserCallback user_callback,
2642 ModestMailOperationPrivate *priv = NULL;
2643 RefreshAsyncHelper *helper = NULL;
2645 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2647 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2649 /* Get account and set it into mail_operation */
2650 priv->account = modest_tny_folder_get_account (folder);
2652 /* Create the helper */
2653 helper = g_slice_new0 (RefreshAsyncHelper);
2654 helper->mail_op = g_object_ref (self);
2655 helper->user_callback = user_callback;
2656 helper->user_data = user_data;
2658 /* Refresh the folder. TODO: tinymail could issue a status
2659 updates before the callback call then this could happen. We
2660 must review the design */
2661 tny_folder_refresh_async (folder,
2663 on_refresh_folder_status_update,
2669 * It's used by the mail operation queue to notify the observers
2670 * attached to that signal that the operation finished. We need to use
2671 * that because tinymail does not give us the progress of a given
2672 * operation when it finishes (it directly calls the operation
2676 modest_mail_operation_notify_end (ModestMailOperation *self)
2678 ModestMailOperationState *state;
2679 ModestMailOperationPrivate *priv = NULL;
2681 g_return_if_fail (self);
2683 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2685 /* Set the account back to not busy */
2686 if (priv->account_name) {
2687 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2688 priv->account_name, FALSE);
2689 g_free(priv->account_name);
2690 priv->account_name = NULL;
2693 /* Notify the observers about the mail operation end */
2694 /* We do not wrapp this emission because we assume that this
2695 function is always called from within the main lock */
2696 state = modest_mail_operation_clone_state (self);
2697 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2698 g_slice_free (ModestMailOperationState, state);