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);
1647 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1649 TnyFolderStore *parent,
1650 gboolean delete_original,
1651 XferMsgsAsynUserCallback user_callback,
1654 ModestMailOperationPrivate *priv = NULL;
1655 ModestTnyFolderRules parent_rules = 0, rules;
1656 XFerMsgAsyncHelper *helper = NULL;
1658 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1659 g_return_if_fail (TNY_IS_FOLDER (folder));
1661 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1663 /* Get account and set it into mail_operation */
1664 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1665 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1667 /* Get folder rules */
1668 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1669 if (TNY_IS_FOLDER (parent))
1670 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1672 /* The moveable restriction is applied also to copy operation */
1673 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1674 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1675 /* Set status failed and set an error */
1676 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1677 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1678 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1679 _("mail_in_ui_folder_move_target_error"));
1681 /* Notify the queue */
1682 modest_mail_operation_notify_end (self);
1683 } else if (TNY_IS_FOLDER (parent) &&
1684 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1685 /* Set status failed and set an error */
1686 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1687 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1688 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1689 _("FIXME: parent folder does not accept new folders"));
1691 /* Notify the queue */
1692 modest_mail_operation_notify_end (self);
1694 /* Create the helper */
1695 helper = g_slice_new0 (XFerMsgAsyncHelper);
1696 helper->mail_op = g_object_ref(self);
1697 helper->dest_folder = NULL;
1698 helper->headers = NULL;
1699 helper->user_callback = user_callback;
1700 helper->user_data = user_data;
1702 /* Move/Copy folder */
1703 tny_folder_copy_async (folder,
1705 tny_folder_get_name (folder),
1708 transfer_folder_status_cb,
1715 modest_mail_operation_rename_folder (ModestMailOperation *self,
1719 ModestMailOperationPrivate *priv;
1720 ModestTnyFolderRules rules;
1721 XFerMsgAsyncHelper *helper;
1723 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1724 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1725 g_return_if_fail (name);
1727 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1729 /* Get account and set it into mail_operation */
1730 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1732 /* Check folder rules */
1733 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1734 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1735 /* Set status failed and set an error */
1736 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1737 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1738 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1739 _("FIXME: unable to rename"));
1741 /* Notify about operation end */
1742 modest_mail_operation_notify_end (self);
1743 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1744 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1745 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1746 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1747 _("FIXME: unable to rename"));
1748 /* Notify about operation end */
1749 modest_mail_operation_notify_end (self);
1751 TnyFolderStore *into;
1753 /* Create the helper */
1754 helper = g_slice_new0 (XFerMsgAsyncHelper);
1755 helper->mail_op = g_object_ref(self);
1756 helper->dest_folder = NULL;
1757 helper->headers = NULL;
1758 helper->user_callback = NULL;
1759 helper->user_data = NULL;
1761 /* Rename. Camel handles folder subscription/unsubscription */
1762 into = tny_folder_get_folder_store (folder);
1763 tny_folder_copy_async (folder, into, name, TRUE,
1765 transfer_folder_status_cb,
1769 g_object_unref (into);
1773 /* ******************************************************************* */
1774 /* ************************** MSG ACTIONS ************************* */
1775 /* ******************************************************************* */
1777 void modest_mail_operation_get_msg (ModestMailOperation *self,
1779 GetMsgAsyncUserCallback user_callback,
1782 GetMsgAsyncHelper *helper = NULL;
1784 ModestMailOperationPrivate *priv;
1786 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1787 g_return_if_fail (TNY_IS_HEADER (header));
1789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1790 folder = tny_header_get_folder (header);
1792 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1794 /* Get message from folder */
1796 /* Get account and set it into mail_operation */
1797 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1799 helper = g_slice_new0 (GetMsgAsyncHelper);
1800 helper->mail_op = self;
1801 helper->user_callback = user_callback;
1802 helper->user_data = user_data;
1803 helper->header = g_object_ref (header);
1805 // The callback's reference so that the mail op is not
1806 // finalized until the async operation is completed even if
1807 // the user canceled the request meanwhile.
1808 g_object_ref (G_OBJECT (helper->mail_op));
1810 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1812 g_object_unref (G_OBJECT (folder));
1814 /* Set status failed and set an error */
1815 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1816 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1817 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1818 _("Error trying to get a message. No folder found for header"));
1820 /* Notify the queue */
1821 modest_mail_operation_notify_end (self);
1826 idle_get_mime_part_size_cb (gpointer userdata)
1828 GetMimePartSizeInfo *idle_info;
1830 idle_info = (GetMimePartSizeInfo *) userdata;
1832 gdk_threads_enter ();
1833 idle_info->callback (idle_info->mail_op,
1835 idle_info->userdata);
1836 gdk_threads_leave ();
1838 g_object_unref (idle_info->mail_op);
1839 g_slice_free (GetMimePartSizeInfo, idle_info);
1845 get_mime_part_size_thread (gpointer thr_user_data)
1847 GetMimePartSizeInfo *info;
1848 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1852 ModestMailOperationPrivate *priv;
1854 info = (GetMimePartSizeInfo *) thr_user_data;
1855 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1857 stream = tny_camel_mem_stream_new ();
1858 tny_mime_part_decode_to_stream (info->mime_part, stream);
1859 tny_stream_reset (stream);
1860 if (tny_stream_is_eos (stream)) {
1861 tny_stream_close (stream);
1862 stream = tny_mime_part_get_stream (info->mime_part);
1865 while (!tny_stream_is_eos (stream)) {
1866 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1867 total += readed_size;
1870 if (info->callback) {
1871 GetMimePartSizeInfo *idle_info;
1873 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1874 idle_info->mail_op = g_object_ref (info->mail_op);
1875 idle_info->size = total;
1876 idle_info->callback = info->callback;
1877 idle_info->userdata = info->userdata;
1878 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1881 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1883 g_object_unref (info->mail_op);
1884 g_object_unref (stream);
1885 g_object_unref (info->mime_part);
1886 g_slice_free (GetMimePartSizeInfo, info);
1892 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1894 GetMimePartSizeCallback user_callback,
1896 GDestroyNotify notify)
1898 GetMimePartSizeInfo *info;
1899 ModestMailOperationPrivate *priv;
1902 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1903 g_return_if_fail (TNY_IS_MIME_PART (part));
1905 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1907 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1908 info = g_slice_new0 (GetMimePartSizeInfo);
1909 info->mail_op = g_object_ref (self);
1910 info->mime_part = g_object_ref (part);
1911 info->callback = user_callback;
1912 info->userdata = user_data;
1914 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1919 get_msg_cb (TnyFolder *folder,
1925 GetMsgAsyncHelper *helper = NULL;
1926 ModestMailOperation *self = NULL;
1927 ModestMailOperationPrivate *priv = NULL;
1929 helper = (GetMsgAsyncHelper *) user_data;
1930 g_return_if_fail (helper != NULL);
1931 self = helper->mail_op;
1932 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1935 /* Check errors and cancel */
1937 priv->error = g_error_copy (*error);
1938 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1939 } else if (cancelled) {
1940 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1941 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1942 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1943 _("Error trying to refresh the contents of %s"),
1944 tny_folder_get_name (folder));
1946 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1949 /* If user defined callback function was defined, call it even
1950 if the operation failed*/
1951 if (helper->user_callback) {
1952 /* This callback is called into an iddle by tinymail,
1953 and idles are not in the main lock */
1954 gdk_threads_enter ();
1955 helper->user_callback (self, helper->header, msg, helper->user_data);
1956 gdk_threads_leave ();
1959 /* Notify about operation end */
1960 modest_mail_operation_notify_end (self);
1962 g_object_unref (helper->mail_op);
1963 g_object_unref (helper->header);
1964 g_slice_free (GetMsgAsyncHelper, helper);
1969 get_msg_status_cb (GObject *obj,
1973 GetMsgAsyncHelper *helper = NULL;
1974 ModestMailOperation *self;
1975 ModestMailOperationPrivate *priv;
1976 ModestMailOperationState *state;
1978 g_return_if_fail (status != NULL);
1979 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1981 helper = (GetMsgAsyncHelper *) user_data;
1982 g_return_if_fail (helper != NULL);
1984 self = helper->mail_op;
1985 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1987 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1988 TnyFolder *folder = tny_header_get_folder (helper->header);
1990 TnyAccount *account;
1991 account = tny_folder_get_account (folder);
1993 tny_account_cancel (account);
1994 g_object_unref (account);
1996 g_object_unref (folder);
2005 state = modest_mail_operation_clone_state (self);
2006 state->bytes_done = status->position;
2007 state->bytes_total = status->of_total;
2008 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2009 g_slice_free (ModestMailOperationState, state);
2012 /****************************************************/
2014 ModestMailOperation *mail_op;
2016 GetMsgAsyncUserCallback user_callback;
2018 GDestroyNotify notify;
2022 GetMsgAsyncUserCallback user_callback;
2026 ModestMailOperation *mail_op;
2027 } NotifyGetMsgsInfo;
2031 * Used by get_msgs_full_thread to call the user_callback for each
2032 * message that has been read
2035 notify_get_msgs_full (gpointer data)
2037 NotifyGetMsgsInfo *info;
2039 info = (NotifyGetMsgsInfo *) data;
2041 /* Call the user callback. Idles are not in the main lock, so
2043 gdk_threads_enter ();
2044 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2045 gdk_threads_leave ();
2047 g_slice_free (NotifyGetMsgsInfo, info);
2053 * Used by get_msgs_full_thread to free al the thread resources and to
2054 * call the destroy function for the passed user_data
2057 get_msgs_full_destroyer (gpointer data)
2059 GetFullMsgsInfo *info;
2061 info = (GetFullMsgsInfo *) data;
2064 gdk_threads_enter ();
2065 info->notify (info->user_data);
2066 gdk_threads_leave ();
2070 g_object_unref (info->headers);
2071 g_slice_free (GetFullMsgsInfo, info);
2077 get_msgs_full_thread (gpointer thr_user_data)
2079 GetFullMsgsInfo *info;
2080 ModestMailOperationPrivate *priv = NULL;
2081 TnyIterator *iter = NULL;
2083 info = (GetFullMsgsInfo *) thr_user_data;
2084 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2086 iter = tny_list_create_iterator (info->headers);
2087 while (!tny_iterator_is_done (iter)) {
2091 header = TNY_HEADER (tny_iterator_get_current (iter));
2092 folder = tny_header_get_folder (header);
2094 /* Get message from folder */
2097 /* The callback will call it per each header */
2098 msg = tny_folder_get_msg (folder, header, &(priv->error));
2101 ModestMailOperationState *state;
2106 /* notify progress */
2107 state = modest_mail_operation_clone_state (info->mail_op);
2108 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2109 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2110 pair, (GDestroyNotify) modest_pair_free);
2112 /* The callback is the responsible for
2113 freeing the message */
2114 if (info->user_callback) {
2115 NotifyGetMsgsInfo *info_notify;
2116 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2117 info_notify->user_callback = info->user_callback;
2118 info_notify->mail_op = info->mail_op;
2119 info_notify->header = g_object_ref (header);
2120 info_notify->msg = g_object_ref (msg);
2121 info_notify->user_data = info->user_data;
2122 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2123 notify_get_msgs_full,
2126 g_object_unref (msg);
2129 /* Set status failed and set an error */
2130 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2131 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2132 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2133 "Error trying to get a message. No folder found for header");
2135 g_object_unref (header);
2136 tny_iterator_next (iter);
2139 /* Set operation status */
2140 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2141 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2143 /* Notify about operation end */
2144 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2146 /* Free thread resources. Will be called after all previous idles */
2147 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2153 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2154 TnyList *header_list,
2155 GetMsgAsyncUserCallback user_callback,
2157 GDestroyNotify notify)
2159 TnyHeader *header = NULL;
2160 TnyFolder *folder = NULL;
2162 ModestMailOperationPrivate *priv = NULL;
2163 GetFullMsgsInfo *info = NULL;
2164 gboolean size_ok = TRUE;
2166 TnyIterator *iter = NULL;
2168 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2170 /* Init mail operation */
2171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2172 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2174 priv->total = tny_list_get_length(header_list);
2176 /* Get account and set it into mail_operation */
2177 if (tny_list_get_length (header_list) >= 1) {
2178 iter = tny_list_create_iterator (header_list);
2179 header = TNY_HEADER (tny_iterator_get_current (iter));
2180 folder = tny_header_get_folder (header);
2181 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2182 g_object_unref (header);
2183 g_object_unref (folder);
2185 if (tny_list_get_length (header_list) == 1) {
2186 g_object_unref (iter);
2191 /* Get msg size limit */
2192 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2193 MODEST_CONF_MSG_SIZE_LIMIT,
2196 g_clear_error (&(priv->error));
2197 max_size = G_MAXINT;
2199 max_size = max_size * KB;
2202 /* Check message size limits. If there is only one message
2203 always retrieve it */
2205 while (!tny_iterator_is_done (iter) && size_ok) {
2206 header = TNY_HEADER (tny_iterator_get_current (iter));
2207 if (tny_header_get_message_size (header) >= max_size)
2209 g_object_unref (header);
2210 tny_iterator_next (iter);
2212 g_object_unref (iter);
2216 /* Create the info */
2217 info = g_slice_new0 (GetFullMsgsInfo);
2218 info->mail_op = self;
2219 info->user_callback = user_callback;
2220 info->user_data = user_data;
2221 info->headers = g_object_ref (header_list);
2222 info->notify = notify;
2224 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2226 /* Set status failed and set an error */
2227 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2228 /* FIXME: the error msg is different for pop */
2229 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2230 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2231 _("emev_ni_ui_imap_msg_size_exceed_error"));
2232 /* Remove from queue and free resources */
2233 modest_mail_operation_notify_end (self);
2241 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2242 gboolean remove_to_trash /*ignored*/)
2245 ModestMailOperationPrivate *priv;
2247 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2248 g_return_if_fail (TNY_IS_HEADER (header));
2250 if (remove_to_trash)
2251 g_warning ("remove to trash is not implemented");
2253 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2254 folder = tny_header_get_folder (header);
2256 /* Get account and set it into mail_operation */
2257 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2259 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2262 tny_folder_remove_msg (folder, header, &(priv->error));
2264 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2265 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2267 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2268 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2269 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2270 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2273 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2279 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2281 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2284 g_object_unref (G_OBJECT (folder));
2286 /* Notify about operation end */
2287 modest_mail_operation_notify_end (self);
2291 transfer_msgs_status_cb (GObject *obj,
2295 XFerMsgAsyncHelper *helper = NULL;
2296 ModestMailOperation *self;
2297 ModestMailOperationPrivate *priv;
2298 ModestMailOperationState *state;
2301 g_return_if_fail (status != NULL);
2302 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2304 helper = (XFerMsgAsyncHelper *) user_data;
2305 g_return_if_fail (helper != NULL);
2307 self = helper->mail_op;
2308 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2310 priv->done = status->position;
2311 priv->total = status->of_total;
2313 state = modest_mail_operation_clone_state (self);
2314 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2315 g_slice_free (ModestMailOperationState, state);
2320 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2322 XFerMsgAsyncHelper *helper;
2323 ModestMailOperation *self;
2324 ModestMailOperationPrivate *priv;
2326 helper = (XFerMsgAsyncHelper *) user_data;
2327 self = helper->mail_op;
2329 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2332 priv->error = g_error_copy (*err);
2334 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2335 } else if (cancelled) {
2336 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2337 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2338 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2339 _("Error trying to refresh the contents of %s"),
2340 tny_folder_get_name (folder));
2343 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2346 /* Notify about operation end */
2347 modest_mail_operation_notify_end (self);
2349 /* If user defined callback function was defined, call it */
2350 if (helper->user_callback) {
2351 gdk_threads_enter ();
2352 helper->user_callback (priv->source, helper->user_data);
2353 gdk_threads_leave ();
2357 g_object_unref (helper->headers);
2358 g_object_unref (helper->dest_folder);
2359 g_object_unref (helper->mail_op);
2360 g_slice_free (XFerMsgAsyncHelper, helper);
2361 g_object_unref (folder);
2366 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2369 gboolean delete_original,
2370 XferMsgsAsynUserCallback user_callback,
2373 ModestMailOperationPrivate *priv;
2375 TnyFolder *src_folder;
2376 XFerMsgAsyncHelper *helper;
2378 ModestTnyFolderRules rules;
2379 const gchar *id1 = NULL;
2380 const gchar *id2 = NULL;
2381 gboolean same_folder = FALSE;
2383 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2384 g_return_if_fail (TNY_IS_LIST (headers));
2385 g_return_if_fail (TNY_IS_FOLDER (folder));
2387 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2390 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2392 /* Apply folder rules */
2393 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2394 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2395 /* Set status failed and set an error */
2396 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2397 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2398 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2399 _CS("ckct_ib_unable_to_paste_here"));
2400 /* Notify the queue */
2401 modest_mail_operation_notify_end (self);
2405 /* Get source folder */
2406 iter = tny_list_create_iterator (headers);
2407 header = TNY_HEADER (tny_iterator_get_current (iter));
2408 src_folder = tny_header_get_folder (header);
2409 g_object_unref (header);
2410 g_object_unref (iter);
2412 /* Check folder source and destination */
2413 id1 = tny_folder_get_id (src_folder);
2414 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2415 same_folder = !g_ascii_strcasecmp (id1, id2);
2417 /* Set status failed and set an error */
2418 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2419 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2420 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2421 _("mcen_ib_unable_to_copy_samefolder"));
2423 /* Notify the queue */
2424 modest_mail_operation_notify_end (self);
2427 g_object_unref (src_folder);
2431 /* Create the helper */
2432 helper = g_slice_new0 (XFerMsgAsyncHelper);
2433 helper->mail_op = g_object_ref(self);
2434 helper->dest_folder = g_object_ref(folder);
2435 helper->headers = g_object_ref(headers);
2436 helper->user_callback = user_callback;
2437 helper->user_data = user_data;
2439 /* Get account and set it into mail_operation */
2440 priv->account = modest_tny_folder_get_account (src_folder);
2442 /* Transfer messages */
2443 tny_folder_transfer_msgs_async (src_folder,
2448 transfer_msgs_status_cb,
2454 on_refresh_folder (TnyFolder *folder,
2459 RefreshAsyncHelper *helper = NULL;
2460 ModestMailOperation *self = NULL;
2461 ModestMailOperationPrivate *priv = NULL;
2463 helper = (RefreshAsyncHelper *) user_data;
2464 self = helper->mail_op;
2465 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2468 priv->error = g_error_copy (*error);
2469 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2474 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2475 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2476 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2477 _("Error trying to refresh the contents of %s"),
2478 tny_folder_get_name (folder));
2482 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2484 /* Call user defined callback, if it exists */
2485 if (helper->user_callback) {
2486 gdk_threads_enter ();
2487 helper->user_callback (self, folder, helper->user_data);
2488 gdk_threads_leave ();
2492 g_object_unref (helper->mail_op);
2493 g_slice_free (RefreshAsyncHelper, helper);
2495 /* Notify about operation end */
2496 modest_mail_operation_notify_end (self);
2500 on_refresh_folder_status_update (GObject *obj,
2504 RefreshAsyncHelper *helper = NULL;
2505 ModestMailOperation *self = NULL;
2506 ModestMailOperationPrivate *priv = NULL;
2507 ModestMailOperationState *state;
2509 g_return_if_fail (user_data != NULL);
2510 g_return_if_fail (status != NULL);
2511 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2513 helper = (RefreshAsyncHelper *) user_data;
2514 self = helper->mail_op;
2515 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2517 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2519 priv->done = status->position;
2520 priv->total = status->of_total;
2522 state = modest_mail_operation_clone_state (self);
2523 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2524 g_slice_free (ModestMailOperationState, state);
2528 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2530 RefreshAsyncUserCallback user_callback,
2533 ModestMailOperationPrivate *priv = NULL;
2534 RefreshAsyncHelper *helper = NULL;
2536 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2538 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2540 /* Get account and set it into mail_operation */
2541 priv->account = modest_tny_folder_get_account (folder);
2543 /* Create the helper */
2544 helper = g_slice_new0 (RefreshAsyncHelper);
2545 helper->mail_op = g_object_ref(self);
2546 helper->user_callback = user_callback;
2547 helper->user_data = user_data;
2549 /* Refresh the folder. TODO: tinymail could issue a status
2550 updates before the callback call then this could happen. We
2551 must review the design */
2552 tny_folder_refresh_async (folder,
2554 on_refresh_folder_status_update,
2560 * It's used by the mail operation queue to notify the observers
2561 * attached to that signal that the operation finished. We need to use
2562 * that because tinymail does not give us the progress of a given
2563 * operation when it finishes (it directly calls the operation
2567 modest_mail_operation_notify_end (ModestMailOperation *self)
2569 ModestMailOperationState *state;
2570 ModestMailOperationPrivate *priv = NULL;
2572 g_return_if_fail (self);
2574 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2576 /* Set the account back to not busy */
2577 if (priv->account_name) {
2578 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2579 priv->account_name, FALSE);
2580 g_free(priv->account_name);
2581 priv->account_name = NULL;
2584 /* Notify the observers about the mail opertation end */
2585 state = modest_mail_operation_clone_state (self);
2586 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2587 g_slice_free (ModestMailOperationState, state);