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-platform-factory.h"
55 #include "modest-marshal.h"
56 #include "modest-error.h"
57 #include "modest-mail-operation.h"
60 #define GET_SIZE_BUFFER_SIZE 128
62 /* 'private'/'protected' functions */
63 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
64 static void modest_mail_operation_init (ModestMailOperation *obj);
65 static void modest_mail_operation_finalize (GObject *obj);
67 static void get_msg_cb (TnyFolder *folder,
73 static void get_msg_status_cb (GObject *obj,
77 static void modest_mail_operation_notify_end (ModestMailOperation *self);
79 static gboolean did_a_cancel = FALSE;
81 enum _ModestMailOperationSignals
83 PROGRESS_CHANGED_SIGNAL,
88 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
89 struct _ModestMailOperationPrivate {
96 ErrorCheckingUserCallback error_checking;
97 gpointer error_checking_user_data;
98 ModestMailOperationStatus status;
99 ModestMailOperationTypeOperation op_type;
102 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
103 MODEST_TYPE_MAIL_OPERATION, \
104 ModestMailOperationPrivate))
106 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
107 priv->status = new_status;\
110 typedef struct _GetMsgAsyncHelper {
111 ModestMailOperation *mail_op;
113 GetMsgAsyncUserCallback user_callback;
117 typedef struct _RefreshAsyncHelper {
118 ModestMailOperation *mail_op;
119 RefreshAsyncUserCallback user_callback;
121 } RefreshAsyncHelper;
123 typedef struct _XFerMsgAsyncHelper
125 ModestMailOperation *mail_op;
127 TnyFolder *dest_folder;
128 XferMsgsAsynUserCallback user_callback;
130 } XFerMsgAsyncHelper;
132 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
136 static void modest_mail_operation_create_msg (ModestMailOperation *self,
137 const gchar *from, const gchar *to,
138 const gchar *cc, const gchar *bcc,
139 const gchar *subject, const gchar *plain_body,
140 const gchar *html_body, const GList *attachments_list,
141 TnyHeaderFlags priority_flags,
142 ModestMailOperationCreateMsgCallback callback,
145 static gboolean idle_notify_queue (gpointer data);
148 ModestMailOperation *mail_op;
156 GList *attachments_list;
157 TnyHeaderFlags priority_flags;
158 ModestMailOperationCreateMsgCallback callback;
164 ModestMailOperation *mail_op;
166 ModestMailOperationCreateMsgCallback callback;
171 static GObjectClass *parent_class = NULL;
173 static guint signals[NUM_SIGNALS] = {0};
176 modest_mail_operation_get_type (void)
178 static GType my_type = 0;
180 static const GTypeInfo my_info = {
181 sizeof(ModestMailOperationClass),
182 NULL, /* base init */
183 NULL, /* base finalize */
184 (GClassInitFunc) modest_mail_operation_class_init,
185 NULL, /* class finalize */
186 NULL, /* class data */
187 sizeof(ModestMailOperation),
189 (GInstanceInitFunc) modest_mail_operation_init,
192 my_type = g_type_register_static (G_TYPE_OBJECT,
193 "ModestMailOperation",
200 modest_mail_operation_class_init (ModestMailOperationClass *klass)
202 GObjectClass *gobject_class;
203 gobject_class = (GObjectClass*) klass;
205 parent_class = g_type_class_peek_parent (klass);
206 gobject_class->finalize = modest_mail_operation_finalize;
208 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
211 * ModestMailOperation::progress-changed
212 * @self: the #MailOperation that emits the signal
213 * @user_data: user data set when the signal handler was connected
215 * Emitted when the progress of a mail operation changes
217 signals[PROGRESS_CHANGED_SIGNAL] =
218 g_signal_new ("progress-changed",
219 G_TYPE_FROM_CLASS (gobject_class),
221 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
223 g_cclosure_marshal_VOID__POINTER,
224 G_TYPE_NONE, 1, G_TYPE_POINTER);
229 modest_mail_operation_init (ModestMailOperation *obj)
231 ModestMailOperationPrivate *priv;
233 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
235 priv->account = NULL;
236 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
237 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
242 priv->error_checking = NULL;
243 priv->error_checking_user_data = NULL;
247 modest_mail_operation_finalize (GObject *obj)
249 ModestMailOperationPrivate *priv;
251 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
256 g_error_free (priv->error);
260 g_object_unref (priv->source);
264 g_object_unref (priv->account);
265 priv->account = NULL;
269 G_OBJECT_CLASS(parent_class)->finalize (obj);
273 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
276 ModestMailOperation *obj;
277 ModestMailOperationPrivate *priv;
279 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
280 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
282 priv->op_type = op_type;
284 priv->source = g_object_ref(source);
290 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
292 ErrorCheckingUserCallback error_handler,
295 ModestMailOperation *obj;
296 ModestMailOperationPrivate *priv;
298 obj = modest_mail_operation_new (op_type, source);
299 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
301 g_return_val_if_fail (error_handler != NULL, obj);
302 priv->error_checking = error_handler;
308 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
310 ModestMailOperationPrivate *priv;
312 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
313 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
315 if (priv->error_checking != NULL)
316 priv->error_checking (self, priv->error_checking_user_data);
320 ModestMailOperationTypeOperation
321 modest_mail_operation_get_type_operation (ModestMailOperation *self)
323 ModestMailOperationPrivate *priv;
325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
327 return priv->op_type;
331 modest_mail_operation_is_mine (ModestMailOperation *self,
334 ModestMailOperationPrivate *priv;
336 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
337 if (priv->source == NULL) return FALSE;
339 return priv->source == me;
343 modest_mail_operation_get_source (ModestMailOperation *self)
345 ModestMailOperationPrivate *priv;
347 g_return_val_if_fail (self, NULL);
349 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
351 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
355 return g_object_ref (priv->source);
358 ModestMailOperationStatus
359 modest_mail_operation_get_status (ModestMailOperation *self)
361 ModestMailOperationPrivate *priv;
363 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
364 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
365 MODEST_MAIL_OPERATION_STATUS_INVALID);
367 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
369 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
370 return MODEST_MAIL_OPERATION_STATUS_INVALID;
377 modest_mail_operation_get_error (ModestMailOperation *self)
379 ModestMailOperationPrivate *priv;
381 g_return_val_if_fail (self, NULL);
382 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
384 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
387 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
395 modest_mail_operation_cancel (ModestMailOperation *self)
397 ModestMailOperationPrivate *priv;
399 if (!MODEST_IS_MAIL_OPERATION (self)) {
400 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
404 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
406 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
413 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
415 /* This emits progress-changed on which the mail operation queue is
416 * listening, so the mail operation is correctly removed from the
417 * queue without further explicit calls. */
418 modest_mail_operation_notify_end (self);
424 modest_mail_operation_get_task_done (ModestMailOperation *self)
426 ModestMailOperationPrivate *priv;
428 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
430 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
435 modest_mail_operation_get_task_total (ModestMailOperation *self)
437 ModestMailOperationPrivate *priv;
439 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
441 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
446 modest_mail_operation_is_finished (ModestMailOperation *self)
448 ModestMailOperationPrivate *priv;
449 gboolean retval = FALSE;
451 if (!MODEST_IS_MAIL_OPERATION (self)) {
452 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
456 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
458 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
459 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
460 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
471 modest_mail_operation_get_id (ModestMailOperation *self)
473 ModestMailOperationPrivate *priv;
475 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
477 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
482 modest_mail_operation_set_id (ModestMailOperation *self,
485 ModestMailOperationPrivate *priv;
487 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
494 * Creates an image of the current state of a mail operation, the
495 * caller must free it
497 static ModestMailOperationState *
498 modest_mail_operation_clone_state (ModestMailOperation *self)
500 ModestMailOperationState *state;
501 ModestMailOperationPrivate *priv;
503 /* FIXME: this should be fixed properly
505 * in some cases, priv was NULL, so checking here to
508 g_return_val_if_fail (self, NULL);
509 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
510 g_return_val_if_fail (priv, NULL);
515 state = g_slice_new (ModestMailOperationState);
517 state->status = priv->status;
518 state->op_type = priv->op_type;
519 state->done = priv->done;
520 state->total = priv->total;
521 state->finished = modest_mail_operation_is_finished (self);
522 state->bytes_done = 0;
523 state->bytes_total = 0;
528 /* ******************************************************************* */
529 /* ************************** SEND ACTIONS ************************* */
530 /* ******************************************************************* */
533 modest_mail_operation_send_mail (ModestMailOperation *self,
534 TnyTransportAccount *transport_account,
537 TnySendQueue *send_queue = NULL;
538 ModestMailOperationPrivate *priv;
540 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
541 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
542 g_return_if_fail (TNY_IS_MSG (msg));
544 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
546 /* Get account and set it into mail_operation */
547 priv->account = g_object_ref (transport_account);
551 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
552 if (!TNY_IS_SEND_QUEUE(send_queue)) {
553 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
554 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
555 "modest: could not find send queue for account\n");
557 /* TODO: connect to the msg-sent in order to know when
558 the mail operation is finished */
559 tny_send_queue_add (send_queue, msg, &(priv->error));
560 /* TODO: we're setting always success, do the check in
562 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
565 /* TODO: do this in the handler of the "msg-sent"
566 signal.Notify about operation end */
567 modest_mail_operation_notify_end (self);
571 idle_create_msg_cb (gpointer idle_data)
573 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
575 gdk_threads_enter ();
576 info->callback (info->mail_op, info->msg, info->userdata);
577 gdk_threads_leave ();
578 g_object_unref (info->mail_op);
580 g_object_unref (info->msg);
581 g_slice_free (CreateMsgIdleInfo, info);
587 create_msg_thread (gpointer thread_data)
589 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
590 TnyMsg *new_msg = NULL;
591 ModestMailOperationPrivate *priv;
593 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
594 if (info->html_body == NULL) {
595 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
596 info->bcc, info->subject, info->plain_body,
597 info->attachments_list); /* FIXME: attachments */
599 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
600 info->bcc, info->subject, info->html_body,
601 info->plain_body, info->attachments_list);
606 /* Set priority flags in message */
607 header = tny_msg_get_header (new_msg);
608 if (info->priority_flags != 0)
609 tny_header_set_flags (header, info->priority_flags);
610 if (info->attachments_list != NULL) {
611 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
613 g_object_unref (G_OBJECT(header));
615 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
616 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
617 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
618 "modest: failed to create a new msg\n");
626 g_free (info->plain_body);
627 g_free (info->html_body);
628 g_free (info->subject);
629 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
630 g_list_free (info->attachments_list);
632 if (info->callback) {
633 CreateMsgIdleInfo *idle_info;
634 idle_info = g_slice_new0 (CreateMsgIdleInfo);
635 idle_info->mail_op = info->mail_op;
636 g_object_ref (info->mail_op);
637 idle_info->msg = new_msg;
639 g_object_ref (new_msg);
640 idle_info->callback = info->callback;
641 idle_info->userdata = info->userdata;
642 g_idle_add (idle_create_msg_cb, idle_info);
644 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
647 g_object_unref (info->mail_op);
648 g_slice_free (CreateMsgInfo, info);
653 modest_mail_operation_create_msg (ModestMailOperation *self,
654 const gchar *from, const gchar *to,
655 const gchar *cc, const gchar *bcc,
656 const gchar *subject, const gchar *plain_body,
657 const gchar *html_body,
658 const GList *attachments_list,
659 TnyHeaderFlags priority_flags,
660 ModestMailOperationCreateMsgCallback callback,
663 CreateMsgInfo *info = NULL;
665 info = g_slice_new0 (CreateMsgInfo);
666 info->mail_op = self;
669 info->from = g_strdup (from);
670 info->to = g_strdup (to);
671 info->cc = g_strdup (cc);
672 info->subject = g_strdup (subject);
673 info->plain_body = g_strdup (plain_body);
674 info->html_body = g_strdup (html_body);
675 info->attachments_list = g_list_copy ((GList *) attachments_list);
676 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
677 info->priority_flags = priority_flags;
679 info->callback = callback;
680 info->userdata = userdata;
682 g_thread_create (create_msg_thread, info, FALSE, NULL);
687 TnyTransportAccount *transport_account;
692 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
696 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
704 /* Call mail operation */
705 modest_mail_operation_send_mail (self, info->transport_account, msg);
707 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
709 if (info->draft_msg != NULL) {
710 header = tny_msg_get_header (info->draft_msg);
711 /* Note: This can fail (with a warning) if the message is not really already in a folder,
712 * because this function requires it to have a UID. */
713 tny_folder_remove_msg (folder, header, NULL);
714 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
715 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
716 g_object_unref (header);
722 g_object_unref (info->draft_msg);
723 if (info->transport_account)
724 g_object_unref (info->transport_account);
725 g_slice_free (SendNewMailInfo, info);
726 modest_mail_operation_notify_end (self);
730 modest_mail_operation_send_new_mail (ModestMailOperation *self,
731 TnyTransportAccount *transport_account,
733 const gchar *from, const gchar *to,
734 const gchar *cc, const gchar *bcc,
735 const gchar *subject, const gchar *plain_body,
736 const gchar *html_body,
737 const GList *attachments_list,
738 TnyHeaderFlags priority_flags)
740 ModestMailOperationPrivate *priv = NULL;
741 SendNewMailInfo *info;
743 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
744 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
746 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
748 /* Check parametters */
750 /* Set status failed and set an error */
751 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
752 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
753 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
754 _("Error trying to send a mail. You need to set at least one recipient"));
757 info = g_slice_new0 (SendNewMailInfo);
758 info->transport_account = transport_account;
759 if (transport_account)
760 g_object_ref (transport_account);
761 info->draft_msg = draft_msg;
763 g_object_ref (draft_msg);
764 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
765 attachments_list, priority_flags,
766 modest_mail_operation_send_new_mail_cb, info);
772 TnyTransportAccount *transport_account;
774 ModestMsgEditWindow *edit_window;
778 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
782 TnyFolder *folder = NULL;
783 TnyHeader *header = NULL;
784 ModestMailOperationPrivate *priv = NULL;
785 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
787 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
789 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
790 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
791 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
792 "modest: failed to create a new msg\n");
796 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
798 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
799 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
800 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
801 "modest: failed to create a new msg\n");
805 if (info->draft_msg != NULL) {
806 header = tny_msg_get_header (info->draft_msg);
807 /* Remove the old draft expunging it */
808 tny_folder_remove_msg (folder, header, NULL);
809 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
810 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
811 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
812 g_object_unref (header);
816 tny_folder_add_msg (folder, msg, &(priv->error));
819 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
821 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
823 if (info->edit_window)
824 modest_msg_edit_window_set_draft (info->edit_window, msg);
829 g_object_unref (G_OBJECT(folder));
830 if (info->edit_window)
831 g_object_unref (G_OBJECT(info->edit_window));
833 g_object_unref (G_OBJECT (info->draft_msg));
834 if (info->transport_account)
835 g_object_unref (G_OBJECT(info->transport_account));
836 g_slice_free (SaveToDraftsInfo, info);
838 modest_mail_operation_notify_end (self);
842 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
843 TnyTransportAccount *transport_account,
845 ModestMsgEditWindow *edit_window,
846 const gchar *from, const gchar *to,
847 const gchar *cc, const gchar *bcc,
848 const gchar *subject, const gchar *plain_body,
849 const gchar *html_body,
850 const GList *attachments_list,
851 TnyHeaderFlags priority_flags)
853 ModestMailOperationPrivate *priv = NULL;
854 SaveToDraftsInfo *info = NULL;
856 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
857 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
859 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
861 /* Get account and set it into mail_operation */
862 priv->account = g_object_ref (transport_account);
864 info = g_slice_new0 (SaveToDraftsInfo);
865 info->transport_account = g_object_ref (transport_account);
866 info->draft_msg = draft_msg;
868 g_object_ref (draft_msg);
869 info->edit_window = edit_window;
871 g_object_ref (edit_window);
873 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
874 attachments_list, priority_flags,
875 modest_mail_operation_save_to_drafts_cb, info);
881 ModestMailOperation *mail_op;
882 TnyStoreAccount *account;
883 TnyTransportAccount *transport_account;
886 gchar *retrieve_type;
888 UpdateAccountCallback callback;
895 ModestMailOperation *mail_op;
896 TnyMimePart *mime_part;
898 GetMimePartSizeCallback callback;
900 } GetMimePartSizeInfo;
902 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
903 /* We use this folder observer to track the headers that have been
904 * added to a folder */
907 TnyList *new_headers;
908 } InternalFolderObserver;
912 } InternalFolderObserverClass;
914 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
916 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
917 internal_folder_observer,
919 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
923 foreach_add_item (gpointer header, gpointer user_data)
925 tny_list_prepend (TNY_LIST (user_data),
926 g_object_ref (G_OBJECT (header)));
929 /* This is the method that looks for new messages in a folder */
931 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
933 InternalFolderObserver *derived = (InternalFolderObserver *)self;
935 TnyFolderChangeChanged changed;
937 changed = tny_folder_change_get_changed (change);
939 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
942 /* Get added headers */
943 list = tny_simple_list_new ();
944 tny_folder_change_get_added_headers (change, list);
946 /* Add them to the folder observer */
947 tny_list_foreach (list, foreach_add_item,
948 derived->new_headers);
950 g_object_unref (G_OBJECT (list));
955 internal_folder_observer_init (InternalFolderObserver *self)
957 self->new_headers = tny_simple_list_new ();
960 internal_folder_observer_finalize (GObject *object)
962 InternalFolderObserver *self;
964 self = (InternalFolderObserver *) object;
965 g_object_unref (self->new_headers);
967 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
970 tny_folder_observer_init (TnyFolderObserverIface *iface)
972 iface->update_func = internal_folder_observer_update;
975 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
977 GObjectClass *object_class;
979 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
980 object_class = (GObjectClass*) klass;
981 object_class->finalize = internal_folder_observer_finalize;
987 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
990 TnyList *folders = tny_simple_list_new ();
992 tny_folder_store_get_folders (store, folders, query, NULL);
993 iter = tny_list_create_iterator (folders);
995 while (!tny_iterator_is_done (iter)) {
997 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
999 tny_list_prepend (all_folders, G_OBJECT (folder));
1000 recurse_folders (folder, query, all_folders);
1001 g_object_unref (G_OBJECT (folder));
1003 tny_iterator_next (iter);
1005 g_object_unref (G_OBJECT (iter));
1006 g_object_unref (G_OBJECT (folders));
1010 * Issues the "progress-changed" signal. The timer won't be removed,
1011 * so you must call g_source_remove to stop the signal emission
1014 idle_notify_progress (gpointer data)
1016 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1017 ModestMailOperationState *state;
1019 state = modest_mail_operation_clone_state (mail_op);
1020 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1021 g_slice_free (ModestMailOperationState, state);
1027 * Issues the "progress-changed" signal and removes the timer. It uses
1028 * a lock to ensure that the progress information of the mail
1029 * operation is not modified while there are notifications pending
1032 idle_notify_progress_once (gpointer data)
1036 pair = (ModestPair *) data;
1038 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1040 /* Free the state and the reference to the mail operation */
1041 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1042 g_object_unref (pair->first);
1048 * Used to notify the queue from the main
1049 * loop. We call it inside an idle call to achieve that
1052 idle_notify_queue (gpointer data)
1054 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1056 /* Do not need to block, the notify end will do it for us */
1057 modest_mail_operation_notify_end (mail_op);
1058 g_object_unref (mail_op);
1064 compare_headers_by_date (gconstpointer a,
1067 TnyHeader **header1, **header2;
1068 time_t sent1, sent2;
1070 header1 = (TnyHeader **) a;
1071 header2 = (TnyHeader **) b;
1073 sent1 = tny_header_get_date_sent (*header1);
1074 sent2 = tny_header_get_date_sent (*header2);
1076 /* We want the most recent ones (greater time_t) at the
1085 set_last_updated_idle (gpointer data)
1087 gdk_threads_enter ();
1089 /* It does not matter if the time is not exactly the same than
1090 the time when this idle was called, it's just an
1091 approximation and it won't be very different */
1092 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1094 MODEST_ACCOUNT_LAST_UPDATED,
1098 gdk_threads_leave ();
1104 idle_update_account_cb (gpointer data)
1106 UpdateAccountInfo *idle_info;
1108 idle_info = (UpdateAccountInfo *) data;
1110 gdk_threads_enter ();
1111 idle_info->callback (idle_info->mail_op,
1112 idle_info->new_headers,
1113 idle_info->user_data);
1114 gdk_threads_leave ();
1117 g_object_unref (idle_info->mail_op);
1125 update_account_thread (gpointer thr_user_data)
1127 static gboolean first_time = TRUE;
1128 UpdateAccountInfo *info;
1129 TnyList *all_folders = NULL;
1130 GPtrArray *new_headers = NULL;
1131 TnyIterator *iter = NULL;
1132 TnyFolderStoreQuery *query = NULL;
1133 ModestMailOperationPrivate *priv = NULL;
1134 ModestTnySendQueue *send_queue = NULL;
1136 info = (UpdateAccountInfo *) thr_user_data;
1137 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1139 /* Get account and set it into mail_operation */
1140 priv->account = g_object_ref (info->account);
1143 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1144 * show any updates unless we do that
1146 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1147 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1149 /* Get all the folders. We can do it synchronously because
1150 we're already running in a different thread than the UI */
1151 all_folders = tny_simple_list_new ();
1152 query = tny_folder_store_query_new ();
1153 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1154 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1159 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1163 iter = tny_list_create_iterator (all_folders);
1164 while (!tny_iterator_is_done (iter)) {
1165 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1167 recurse_folders (folder, query, all_folders);
1168 tny_iterator_next (iter);
1170 g_object_unref (G_OBJECT (iter));
1172 /* Update status and notify. We need to call the notification
1173 with a source function in order to call it from the main
1174 loop. We need that in order not to get into trouble with
1175 Gtk+. We use a timeout in order to provide more status
1176 information, because the sync tinymail call does not
1177 provide it for the moment */
1178 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1180 /* Refresh folders */
1181 new_headers = g_ptr_array_new ();
1182 iter = tny_list_create_iterator (all_folders);
1184 while (!tny_iterator_is_done (iter) && !priv->error && !did_a_cancel) {
1186 InternalFolderObserver *observer;
1187 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1189 /* Refresh the folder */
1190 /* Our observer receives notification of new emails during folder refreshes,
1191 * so we can use observer->new_headers.
1193 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1194 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1196 /* This gets the status information (headers) from the server.
1197 * We use the blocking version, because we are already in a separate
1201 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1202 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1205 /* If the retrieve type is full messages, refresh and get the messages */
1206 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1208 iter = tny_list_create_iterator (observer->new_headers);
1209 while (!tny_iterator_is_done (iter)) {
1210 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1212 /* Apply per-message size limits */
1213 if (tny_header_get_message_size (header) < info->max_size)
1214 g_ptr_array_add (new_headers, g_object_ref (header));
1216 g_object_unref (header);
1217 tny_iterator_next (iter);
1219 g_object_unref (iter);
1221 /* We do not need to do it the first time
1222 because it's automatically done by the tree
1224 if (G_UNLIKELY (!first_time))
1225 tny_folder_poke_status (TNY_FOLDER (folder));
1227 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1228 g_object_unref (observer);
1231 g_object_unref (G_OBJECT (folder));
1234 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1238 tny_iterator_next (iter);
1241 did_a_cancel = FALSE;
1243 g_object_unref (G_OBJECT (iter));
1244 g_source_remove (timeout);
1246 if (new_headers->len > 0) {
1250 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1252 /* Apply message count limit */
1253 /* If the number of messages exceeds the maximum, ask the
1254 * user to download them all,
1255 * as per the UI spec "Retrieval Limits" section in 4.4:
1257 if (new_headers->len > info->retrieve_limit) {
1258 /* TODO: Ask the user, instead of just
1260 * mail_nc_msg_count_limit_exceeded, with 'Get
1261 * all' and 'Newest only' buttons. */
1262 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1263 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1264 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1265 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1266 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1271 priv->total = MIN (new_headers->len, info->retrieve_limit);
1272 while (msg_num < priv->total) {
1274 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1275 TnyFolder *folder = tny_header_get_folder (header);
1276 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1277 ModestMailOperationState *state;
1281 /* We can not just use the mail operation because the
1282 values of done and total could change before the
1284 state = modest_mail_operation_clone_state (info->mail_op);
1285 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1286 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1287 pair, (GDestroyNotify) modest_pair_free);
1289 g_object_unref (msg);
1290 g_object_unref (folder);
1294 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1295 g_ptr_array_free (new_headers, FALSE);
1298 /* Perform send (if operation was not cancelled) */
1299 if (did_a_cancel) goto out;
1300 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1303 if (priv->account != NULL)
1304 g_object_unref (priv->account);
1305 priv->account = g_object_ref (info->transport_account);
1307 send_queue = modest_runtime_get_send_queue (info->transport_account);
1309 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1310 modest_tny_send_queue_try_to_send (send_queue);
1311 /* g_source_remove (timeout); */
1313 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1314 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1315 "cannot create a send queue for %s\n",
1316 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1317 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1320 /* Check if the operation was a success */
1322 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1324 /* Update the last updated key */
1325 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1326 set_last_updated_idle,
1327 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1328 (GDestroyNotify) g_free);
1333 if (info->callback) {
1334 UpdateAccountInfo *idle_info;
1336 /* This thread is not in the main lock */
1337 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1338 idle_info->mail_op = g_object_ref (info->mail_op);
1339 idle_info->new_headers = (new_headers) ? new_headers->len : 0;
1340 idle_info->callback = info->callback;
1341 g_idle_add (idle_update_account_cb, idle_info);
1344 /* Notify about operation end. Note that the info could be
1345 freed before this idle happens, but the mail operation will
1347 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1350 g_object_unref (query);
1351 g_object_unref (all_folders);
1352 g_object_unref (info->account);
1353 g_object_unref (info->transport_account);
1354 g_free (info->retrieve_type);
1355 g_slice_free (UpdateAccountInfo, info);
1363 modest_mail_operation_update_account (ModestMailOperation *self,
1364 const gchar *account_name,
1365 UpdateAccountCallback callback,
1369 UpdateAccountInfo *info;
1370 ModestMailOperationPrivate *priv;
1371 ModestAccountMgr *mgr;
1372 TnyStoreAccount *modest_account;
1373 TnyTransportAccount *transport_account;
1375 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1376 g_return_val_if_fail (account_name, FALSE);
1378 /* Init mail operation. Set total and done to 0, and do not
1379 update them, this way the progress objects will know that
1380 we have no clue about the number of the objects */
1381 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1384 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1386 /* Make sure that we have a connection, and request one
1388 * TODO: Is there some way to trigger this for every attempt to
1389 * use the network? */
1390 if (!modest_platform_connect_and_wait (NULL))
1393 /* Get the Modest account */
1394 modest_account = (TnyStoreAccount *)
1395 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1397 TNY_ACCOUNT_TYPE_STORE);
1399 if (!modest_account) {
1400 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1401 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1402 "cannot get tny store account for %s\n", account_name);
1407 /* Get the transport account, we can not do it in the thread
1408 due to some problems with dbus */
1409 transport_account = (TnyTransportAccount *)
1410 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1412 if (!transport_account) {
1413 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1414 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1415 "cannot get tny transport account for %s\n", account_name);
1419 /* Create the helper object */
1420 info = g_slice_new (UpdateAccountInfo);
1421 info->mail_op = self;
1422 info->account = modest_account;
1423 info->transport_account = transport_account;
1424 info->callback = callback;
1425 info->user_data = user_data;
1427 /* Get the message size limit */
1428 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1429 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1430 if (info->max_size == 0)
1431 info->max_size = G_MAXINT;
1433 info->max_size = info->max_size * KB;
1435 /* Get per-account retrieval type */
1436 mgr = modest_runtime_get_account_mgr ();
1437 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1438 MODEST_ACCOUNT_RETRIEVE, FALSE);
1440 /* Get per-account message amount retrieval limit */
1441 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1442 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1443 if (info->retrieve_limit == 0)
1444 info->retrieve_limit = G_MAXINT;
1446 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1448 /* Set account busy */
1449 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1450 priv->account_name = g_strdup(account_name);
1452 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1457 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1459 callback (self, 0, user_data);
1460 modest_mail_operation_notify_end (self);
1464 /* ******************************************************************* */
1465 /* ************************** STORE ACTIONS ************************* */
1466 /* ******************************************************************* */
1470 modest_mail_operation_create_folder (ModestMailOperation *self,
1471 TnyFolderStore *parent,
1474 ModestMailOperationPrivate *priv;
1475 TnyFolder *new_folder = NULL;
1477 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1478 g_return_val_if_fail (name, NULL);
1480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1483 if (TNY_IS_FOLDER (parent)) {
1484 /* Check folder rules */
1485 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1486 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1487 /* Set status failed and set an error */
1488 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1489 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1490 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1491 _("mail_in_ui_folder_create_error"));
1495 if (!strcmp (name, " ") || strchr (name, '/')) {
1496 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1497 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1498 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1499 _("mail_in_ui_folder_create_error"));
1503 /* Create the folder */
1504 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1505 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1507 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1510 /* Notify about operation end */
1511 modest_mail_operation_notify_end (self);
1517 modest_mail_operation_remove_folder (ModestMailOperation *self,
1519 gboolean remove_to_trash)
1521 TnyAccount *account;
1522 ModestMailOperationPrivate *priv;
1523 ModestTnyFolderRules rules;
1525 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1526 g_return_if_fail (TNY_IS_FOLDER (folder));
1528 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1530 /* Check folder rules */
1531 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1532 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1533 /* Set status failed and set an error */
1534 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1535 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1536 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1537 _("mail_in_ui_folder_delete_error"));
1541 /* Get the account */
1542 account = modest_tny_folder_get_account (folder);
1543 priv->account = g_object_ref(account);
1545 /* Delete folder or move to trash */
1546 if (remove_to_trash) {
1547 TnyFolder *trash_folder = NULL;
1548 trash_folder = modest_tny_account_get_special_folder (account,
1549 TNY_FOLDER_TYPE_TRASH);
1550 /* TODO: error_handling */
1551 modest_mail_operation_xfer_folder (self, folder,
1552 TNY_FOLDER_STORE (trash_folder),
1555 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1557 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1558 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1561 g_object_unref (G_OBJECT (parent));
1563 g_object_unref (G_OBJECT (account));
1566 /* Notify about operation end */
1567 modest_mail_operation_notify_end (self);
1571 transfer_folder_status_cb (GObject *obj,
1575 ModestMailOperation *self;
1576 ModestMailOperationPrivate *priv;
1577 ModestMailOperationState *state;
1578 XFerMsgAsyncHelper *helper;
1580 g_return_if_fail (status != NULL);
1581 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1583 helper = (XFerMsgAsyncHelper *) user_data;
1584 g_return_if_fail (helper != NULL);
1586 self = helper->mail_op;
1587 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1589 priv->done = status->position;
1590 priv->total = status->of_total;
1592 state = modest_mail_operation_clone_state (self);
1593 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1594 g_slice_free (ModestMailOperationState, state);
1599 transfer_folder_cb (TnyFolder *folder,
1600 TnyFolderStore *into,
1602 TnyFolder *new_folder,
1606 XFerMsgAsyncHelper *helper;
1607 ModestMailOperation *self = NULL;
1608 ModestMailOperationPrivate *priv = NULL;
1610 helper = (XFerMsgAsyncHelper *) user_data;
1611 g_return_if_fail (helper != NULL);
1613 self = helper->mail_op;
1614 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1617 priv->error = g_error_copy (*err);
1619 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1620 } else if (cancelled) {
1621 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1622 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1623 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1624 _("Transference of %s was cancelled."),
1625 tny_folder_get_name (folder));
1628 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1631 /* Notify about operation end */
1632 modest_mail_operation_notify_end (self);
1634 /* If user defined callback function was defined, call it */
1635 if (helper->user_callback) {
1636 gdk_threads_enter ();
1637 helper->user_callback (priv->source, helper->user_data);
1638 gdk_threads_leave ();
1642 g_object_unref (helper->mail_op);
1643 g_slice_free (XFerMsgAsyncHelper, helper);
1644 g_object_unref (folder);
1645 g_object_unref (into);
1649 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1651 TnyFolderStore *parent,
1652 gboolean delete_original,
1653 XferMsgsAsynUserCallback user_callback,
1656 ModestMailOperationPrivate *priv = NULL;
1657 ModestTnyFolderRules parent_rules = 0, rules;
1658 XFerMsgAsyncHelper *helper = NULL;
1660 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1661 g_return_if_fail (TNY_IS_FOLDER (folder));
1663 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1665 /* Get account and set it into mail_operation */
1666 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1667 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1669 /* Get folder rules */
1670 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1671 if (TNY_IS_FOLDER (parent))
1672 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1674 /* The moveable restriction is applied also to copy operation */
1675 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1676 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1677 /* Set status failed and set an error */
1678 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1679 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1680 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1681 _("mail_in_ui_folder_move_target_error"));
1683 /* Notify the queue */
1684 modest_mail_operation_notify_end (self);
1685 } else if (TNY_IS_FOLDER (parent) &&
1686 (parent_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 _("FIXME: parent folder does not accept new folders"));
1693 /* Notify the queue */
1694 modest_mail_operation_notify_end (self);
1696 /* Pick references for async calls */
1697 g_object_ref (folder);
1698 g_object_ref (parent);
1700 /* Create the helper */
1701 helper = g_slice_new0 (XFerMsgAsyncHelper);
1702 helper->mail_op = g_object_ref(self);
1703 helper->dest_folder = NULL;
1704 helper->headers = NULL;
1705 helper->user_callback = user_callback;
1706 helper->user_data = user_data;
1708 /* Move/Copy folder */
1709 tny_folder_copy_async (folder,
1711 tny_folder_get_name (folder),
1714 transfer_folder_status_cb,
1721 modest_mail_operation_rename_folder (ModestMailOperation *self,
1725 ModestMailOperationPrivate *priv;
1726 ModestTnyFolderRules rules;
1727 XFerMsgAsyncHelper *helper;
1729 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1730 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1731 g_return_if_fail (name);
1733 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1735 /* Get account and set it into mail_operation */
1736 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1738 /* Check folder rules */
1739 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1740 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1741 /* Set status failed and set an error */
1742 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1743 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1744 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1745 _("FIXME: unable to rename"));
1747 /* Notify about operation end */
1748 modest_mail_operation_notify_end (self);
1749 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1750 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1751 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1752 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1753 _("FIXME: unable to rename"));
1754 /* Notify about operation end */
1755 modest_mail_operation_notify_end (self);
1757 TnyFolderStore *into;
1759 /* Create the helper */
1760 helper = g_slice_new0 (XFerMsgAsyncHelper);
1761 helper->mail_op = g_object_ref(self);
1762 helper->dest_folder = NULL;
1763 helper->headers = NULL;
1764 helper->user_callback = NULL;
1765 helper->user_data = NULL;
1767 /* Rename. Camel handles folder subscription/unsubscription */
1768 into = tny_folder_get_folder_store (folder);
1769 tny_folder_copy_async (folder, into, name, TRUE,
1771 transfer_folder_status_cb,
1775 g_object_unref (into);
1779 /* ******************************************************************* */
1780 /* ************************** MSG ACTIONS ************************* */
1781 /* ******************************************************************* */
1783 void modest_mail_operation_get_msg (ModestMailOperation *self,
1785 GetMsgAsyncUserCallback user_callback,
1788 GetMsgAsyncHelper *helper = NULL;
1790 ModestMailOperationPrivate *priv;
1792 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1793 g_return_if_fail (TNY_IS_HEADER (header));
1795 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1796 folder = tny_header_get_folder (header);
1798 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1800 /* Get message from folder */
1802 /* Get account and set it into mail_operation */
1803 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1805 helper = g_slice_new0 (GetMsgAsyncHelper);
1806 helper->mail_op = self;
1807 helper->user_callback = user_callback;
1808 helper->user_data = user_data;
1809 helper->header = g_object_ref (header);
1811 // The callback's reference so that the mail op is not
1812 // finalized until the async operation is completed even if
1813 // the user canceled the request meanwhile.
1814 g_object_ref (G_OBJECT (helper->mail_op));
1816 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1818 g_object_unref (G_OBJECT (folder));
1820 /* Set status failed and set an error */
1821 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1822 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1823 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1824 _("Error trying to get a message. No folder found for header"));
1826 /* Notify the queue */
1827 modest_mail_operation_notify_end (self);
1832 idle_get_mime_part_size_cb (gpointer userdata)
1834 GetMimePartSizeInfo *idle_info;
1836 idle_info = (GetMimePartSizeInfo *) userdata;
1838 gdk_threads_enter ();
1839 idle_info->callback (idle_info->mail_op,
1841 idle_info->userdata);
1842 gdk_threads_leave ();
1844 g_object_unref (idle_info->mail_op);
1845 g_slice_free (GetMimePartSizeInfo, idle_info);
1851 get_mime_part_size_thread (gpointer thr_user_data)
1853 GetMimePartSizeInfo *info;
1854 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1858 ModestMailOperationPrivate *priv;
1860 info = (GetMimePartSizeInfo *) thr_user_data;
1861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1863 stream = tny_camel_mem_stream_new ();
1864 tny_mime_part_decode_to_stream (info->mime_part, stream);
1865 tny_stream_reset (stream);
1866 if (tny_stream_is_eos (stream)) {
1867 tny_stream_close (stream);
1868 stream = tny_mime_part_get_stream (info->mime_part);
1871 while (!tny_stream_is_eos (stream)) {
1872 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1873 total += readed_size;
1876 if (info->callback) {
1877 GetMimePartSizeInfo *idle_info;
1879 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1880 idle_info->mail_op = g_object_ref (info->mail_op);
1881 idle_info->size = total;
1882 idle_info->callback = info->callback;
1883 idle_info->userdata = info->userdata;
1884 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1887 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1889 g_object_unref (info->mail_op);
1890 g_object_unref (stream);
1891 g_object_unref (info->mime_part);
1892 g_slice_free (GetMimePartSizeInfo, info);
1898 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1900 GetMimePartSizeCallback user_callback,
1902 GDestroyNotify notify)
1904 GetMimePartSizeInfo *info;
1905 ModestMailOperationPrivate *priv;
1908 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1909 g_return_if_fail (TNY_IS_MIME_PART (part));
1911 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1913 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1914 info = g_slice_new0 (GetMimePartSizeInfo);
1915 info->mail_op = g_object_ref (self);
1916 info->mime_part = g_object_ref (part);
1917 info->callback = user_callback;
1918 info->userdata = user_data;
1920 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1925 get_msg_cb (TnyFolder *folder,
1931 GetMsgAsyncHelper *helper = NULL;
1932 ModestMailOperation *self = NULL;
1933 ModestMailOperationPrivate *priv = NULL;
1935 helper = (GetMsgAsyncHelper *) user_data;
1936 g_return_if_fail (helper != NULL);
1937 self = helper->mail_op;
1938 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1939 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1941 /* Check errors and cancel */
1943 priv->error = g_error_copy (*error);
1944 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1945 } else if (cancelled) {
1946 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1947 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1948 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1949 _("Error trying to refresh the contents of %s"),
1950 tny_folder_get_name (folder));
1952 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1955 /* If user defined callback function was defined, call it even
1956 if the operation failed*/
1957 if (helper->user_callback) {
1958 /* This callback is called into an iddle by tinymail,
1959 and idles are not in the main lock */
1960 gdk_threads_enter ();
1961 helper->user_callback (self, helper->header, msg, helper->user_data);
1962 gdk_threads_leave ();
1965 /* Notify about operation end */
1966 modest_mail_operation_notify_end (self);
1968 g_object_unref (helper->mail_op);
1969 g_object_unref (helper->header);
1970 g_slice_free (GetMsgAsyncHelper, helper);
1975 get_msg_status_cb (GObject *obj,
1979 GetMsgAsyncHelper *helper = NULL;
1980 ModestMailOperation *self;
1981 ModestMailOperationPrivate *priv;
1982 ModestMailOperationState *state;
1984 g_return_if_fail (status != NULL);
1985 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1987 helper = (GetMsgAsyncHelper *) user_data;
1988 g_return_if_fail (helper != NULL);
1990 self = helper->mail_op;
1991 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1993 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1994 TnyFolder *folder = tny_header_get_folder (helper->header);
1996 TnyAccount *account;
1997 account = tny_folder_get_account (folder);
1999 tny_account_cancel (account);
2000 g_object_unref (account);
2002 g_object_unref (folder);
2011 state = modest_mail_operation_clone_state (self);
2012 state->bytes_done = status->position;
2013 state->bytes_total = status->of_total;
2014 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2015 g_slice_free (ModestMailOperationState, state);
2018 /****************************************************/
2020 ModestMailOperation *mail_op;
2022 GetMsgAsyncUserCallback user_callback;
2024 GDestroyNotify notify;
2028 GetMsgAsyncUserCallback user_callback;
2032 ModestMailOperation *mail_op;
2033 } NotifyGetMsgsInfo;
2037 * Used by get_msgs_full_thread to call the user_callback for each
2038 * message that has been read
2041 notify_get_msgs_full (gpointer data)
2043 NotifyGetMsgsInfo *info;
2045 info = (NotifyGetMsgsInfo *) data;
2047 /* Call the user callback. Idles are not in the main lock, so
2049 gdk_threads_enter ();
2050 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2051 gdk_threads_leave ();
2053 g_slice_free (NotifyGetMsgsInfo, info);
2059 * Used by get_msgs_full_thread to free al the thread resources and to
2060 * call the destroy function for the passed user_data
2063 get_msgs_full_destroyer (gpointer data)
2065 GetFullMsgsInfo *info;
2067 info = (GetFullMsgsInfo *) data;
2070 gdk_threads_enter ();
2071 info->notify (info->user_data);
2072 gdk_threads_leave ();
2076 g_object_unref (info->headers);
2077 g_slice_free (GetFullMsgsInfo, info);
2083 get_msgs_full_thread (gpointer thr_user_data)
2085 GetFullMsgsInfo *info;
2086 ModestMailOperationPrivate *priv = NULL;
2087 TnyIterator *iter = NULL;
2089 info = (GetFullMsgsInfo *) thr_user_data;
2090 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2092 iter = tny_list_create_iterator (info->headers);
2093 while (!tny_iterator_is_done (iter)) {
2097 header = TNY_HEADER (tny_iterator_get_current (iter));
2098 folder = tny_header_get_folder (header);
2100 /* Get message from folder */
2103 /* The callback will call it per each header */
2104 msg = tny_folder_get_msg (folder, header, &(priv->error));
2107 ModestMailOperationState *state;
2112 /* notify progress */
2113 state = modest_mail_operation_clone_state (info->mail_op);
2114 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2115 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2116 pair, (GDestroyNotify) modest_pair_free);
2118 /* The callback is the responsible for
2119 freeing the message */
2120 if (info->user_callback) {
2121 NotifyGetMsgsInfo *info_notify;
2122 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2123 info_notify->user_callback = info->user_callback;
2124 info_notify->mail_op = info->mail_op;
2125 info_notify->header = g_object_ref (header);
2126 info_notify->msg = g_object_ref (msg);
2127 info_notify->user_data = info->user_data;
2128 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2129 notify_get_msgs_full,
2132 g_object_unref (msg);
2135 /* Set status failed and set an error */
2136 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2137 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2138 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2139 "Error trying to get a message. No folder found for header");
2141 g_object_unref (header);
2142 tny_iterator_next (iter);
2145 /* Set operation status */
2146 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2147 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2149 /* Notify about operation end */
2150 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2152 /* Free thread resources. Will be called after all previous idles */
2153 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2159 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2160 TnyList *header_list,
2161 GetMsgAsyncUserCallback user_callback,
2163 GDestroyNotify notify)
2165 TnyHeader *header = NULL;
2166 TnyFolder *folder = NULL;
2168 ModestMailOperationPrivate *priv = NULL;
2169 GetFullMsgsInfo *info = NULL;
2170 gboolean size_ok = TRUE;
2172 TnyIterator *iter = NULL;
2174 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2176 /* Init mail operation */
2177 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2178 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2180 priv->total = tny_list_get_length(header_list);
2182 /* Get account and set it into mail_operation */
2183 if (tny_list_get_length (header_list) >= 1) {
2184 iter = tny_list_create_iterator (header_list);
2185 header = TNY_HEADER (tny_iterator_get_current (iter));
2186 folder = tny_header_get_folder (header);
2187 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2188 g_object_unref (header);
2189 g_object_unref (folder);
2191 if (tny_list_get_length (header_list) == 1) {
2192 g_object_unref (iter);
2197 /* Get msg size limit */
2198 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2199 MODEST_CONF_MSG_SIZE_LIMIT,
2202 g_clear_error (&(priv->error));
2203 max_size = G_MAXINT;
2205 max_size = max_size * KB;
2208 /* Check message size limits. If there is only one message
2209 always retrieve it */
2211 while (!tny_iterator_is_done (iter) && size_ok) {
2212 header = TNY_HEADER (tny_iterator_get_current (iter));
2213 if (tny_header_get_message_size (header) >= max_size)
2215 g_object_unref (header);
2216 tny_iterator_next (iter);
2218 g_object_unref (iter);
2222 /* Create the info */
2223 info = g_slice_new0 (GetFullMsgsInfo);
2224 info->mail_op = self;
2225 info->user_callback = user_callback;
2226 info->user_data = user_data;
2227 info->headers = g_object_ref (header_list);
2228 info->notify = notify;
2230 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2232 /* Set status failed and set an error */
2233 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2234 /* FIXME: the error msg is different for pop */
2235 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2236 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2237 _("emev_ni_ui_imap_msg_size_exceed_error"));
2238 /* Remove from queue and free resources */
2239 modest_mail_operation_notify_end (self);
2247 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2248 gboolean remove_to_trash /*ignored*/)
2251 ModestMailOperationPrivate *priv;
2253 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2254 g_return_if_fail (TNY_IS_HEADER (header));
2256 if (remove_to_trash)
2257 g_warning ("remove to trash is not implemented");
2259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2260 folder = tny_header_get_folder (header);
2262 /* Get account and set it into mail_operation */
2263 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2265 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2268 tny_folder_remove_msg (folder, header, &(priv->error));
2270 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2271 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2273 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2274 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2275 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2276 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2279 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2285 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2287 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2290 g_object_unref (G_OBJECT (folder));
2292 /* Notify about operation end */
2293 modest_mail_operation_notify_end (self);
2297 transfer_msgs_status_cb (GObject *obj,
2301 XFerMsgAsyncHelper *helper = NULL;
2302 ModestMailOperation *self;
2303 ModestMailOperationPrivate *priv;
2304 ModestMailOperationState *state;
2307 g_return_if_fail (status != NULL);
2308 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2310 helper = (XFerMsgAsyncHelper *) user_data;
2311 g_return_if_fail (helper != NULL);
2313 self = helper->mail_op;
2314 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2316 priv->done = status->position;
2317 priv->total = status->of_total;
2319 state = modest_mail_operation_clone_state (self);
2320 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2321 g_slice_free (ModestMailOperationState, state);
2326 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2328 XFerMsgAsyncHelper *helper;
2329 ModestMailOperation *self;
2330 ModestMailOperationPrivate *priv;
2332 helper = (XFerMsgAsyncHelper *) user_data;
2333 self = helper->mail_op;
2335 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2338 priv->error = g_error_copy (*err);
2340 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2341 } else if (cancelled) {
2342 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2343 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2344 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2345 _("Error trying to refresh the contents of %s"),
2346 tny_folder_get_name (folder));
2349 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2352 /* Notify about operation end */
2353 modest_mail_operation_notify_end (self);
2355 /* If user defined callback function was defined, call it */
2356 if (helper->user_callback) {
2357 gdk_threads_enter ();
2358 helper->user_callback (priv->source, helper->user_data);
2359 gdk_threads_leave ();
2363 g_object_unref (helper->headers);
2364 g_object_unref (helper->dest_folder);
2365 g_object_unref (helper->mail_op);
2366 g_slice_free (XFerMsgAsyncHelper, helper);
2367 g_object_unref (folder);
2372 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2375 gboolean delete_original,
2376 XferMsgsAsynUserCallback user_callback,
2379 ModestMailOperationPrivate *priv;
2381 TnyFolder *src_folder;
2382 XFerMsgAsyncHelper *helper;
2384 ModestTnyFolderRules rules;
2385 const gchar *id1 = NULL;
2386 const gchar *id2 = NULL;
2387 gboolean same_folder = FALSE;
2389 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2390 g_return_if_fail (TNY_IS_LIST (headers));
2391 g_return_if_fail (TNY_IS_FOLDER (folder));
2393 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2396 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2398 /* Apply folder rules */
2399 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2400 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2401 /* Set status failed and set an error */
2402 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2403 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2404 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2405 _CS("ckct_ib_unable_to_paste_here"));
2406 /* Notify the queue */
2407 modest_mail_operation_notify_end (self);
2411 /* Get source folder */
2412 iter = tny_list_create_iterator (headers);
2413 header = TNY_HEADER (tny_iterator_get_current (iter));
2414 src_folder = tny_header_get_folder (header);
2415 g_object_unref (header);
2416 g_object_unref (iter);
2418 /* Check folder source and destination */
2419 id1 = tny_folder_get_id (src_folder);
2420 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2421 same_folder = !g_ascii_strcasecmp (id1, id2);
2423 /* Set status failed and set an error */
2424 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2425 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2426 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2427 _("mcen_ib_unable_to_copy_samefolder"));
2429 /* Notify the queue */
2430 modest_mail_operation_notify_end (self);
2433 g_object_unref (src_folder);
2437 /* Create the helper */
2438 helper = g_slice_new0 (XFerMsgAsyncHelper);
2439 helper->mail_op = g_object_ref(self);
2440 helper->dest_folder = g_object_ref(folder);
2441 helper->headers = g_object_ref(headers);
2442 helper->user_callback = user_callback;
2443 helper->user_data = user_data;
2445 /* Get account and set it into mail_operation */
2446 priv->account = modest_tny_folder_get_account (src_folder);
2448 /* Transfer messages */
2449 tny_folder_transfer_msgs_async (src_folder,
2454 transfer_msgs_status_cb,
2460 on_refresh_folder (TnyFolder *folder,
2465 RefreshAsyncHelper *helper = NULL;
2466 ModestMailOperation *self = NULL;
2467 ModestMailOperationPrivate *priv = NULL;
2469 helper = (RefreshAsyncHelper *) user_data;
2470 self = helper->mail_op;
2471 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2474 priv->error = g_error_copy (*error);
2475 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2480 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2481 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2482 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2483 _("Error trying to refresh the contents of %s"),
2484 tny_folder_get_name (folder));
2488 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2490 /* Call user defined callback, if it exists */
2491 if (helper->user_callback) {
2492 gdk_threads_enter ();
2493 helper->user_callback (self, folder, helper->user_data);
2494 gdk_threads_leave ();
2498 g_object_unref (helper->mail_op);
2499 g_slice_free (RefreshAsyncHelper, helper);
2500 g_object_unref (folder);
2502 /* Notify about operation end */
2503 modest_mail_operation_notify_end (self);
2507 on_refresh_folder_status_update (GObject *obj,
2511 RefreshAsyncHelper *helper = NULL;
2512 ModestMailOperation *self = NULL;
2513 ModestMailOperationPrivate *priv = NULL;
2514 ModestMailOperationState *state;
2516 g_return_if_fail (user_data != NULL);
2517 g_return_if_fail (status != NULL);
2518 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2520 helper = (RefreshAsyncHelper *) user_data;
2521 self = helper->mail_op;
2522 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2524 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2526 priv->done = status->position;
2527 priv->total = status->of_total;
2529 state = modest_mail_operation_clone_state (self);
2530 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2531 g_slice_free (ModestMailOperationState, state);
2535 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2537 RefreshAsyncUserCallback user_callback,
2540 ModestMailOperationPrivate *priv = NULL;
2541 RefreshAsyncHelper *helper = NULL;
2543 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2545 /* Pick a reference */
2546 g_object_ref (folder);
2548 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2550 /* Get account and set it into mail_operation */
2551 priv->account = modest_tny_folder_get_account (folder);
2553 /* Create the helper */
2554 helper = g_slice_new0 (RefreshAsyncHelper);
2555 helper->mail_op = g_object_ref(self);
2556 helper->user_callback = user_callback;
2557 helper->user_data = user_data;
2559 /* Refresh the folder. TODO: tinymail could issue a status
2560 updates before the callback call then this could happen. We
2561 must review the design */
2562 tny_folder_refresh_async (folder,
2564 on_refresh_folder_status_update,
2570 * It's used by the mail operation queue to notify the observers
2571 * attached to that signal that the operation finished. We need to use
2572 * that because tinymail does not give us the progress of a given
2573 * operation when it finishes (it directly calls the operation
2577 modest_mail_operation_notify_end (ModestMailOperation *self)
2579 ModestMailOperationState *state;
2580 ModestMailOperationPrivate *priv = NULL;
2582 g_return_if_fail (self);
2584 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2586 /* Set the account back to not busy */
2587 if (priv->account_name) {
2588 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2589 priv->account_name, FALSE);
2590 g_free(priv->account_name);
2591 priv->account_name = NULL;
2594 /* Notify the observers about the mail opertation end */
2595 state = modest_mail_operation_clone_state (self);
2596 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2597 g_slice_free (ModestMailOperationState, state);