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 TnyList *list = tny_simple_list_new ();
1478 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1480 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1481 g_return_val_if_fail (name, NULL);
1483 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1485 /* Check for already existing folder */
1486 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1487 tny_folder_store_get_folders (parent, list, query, NULL);
1488 g_object_unref (G_OBJECT (query));
1490 if (tny_list_get_length (list) > 0) {
1491 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1492 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1493 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1494 _CS("ckdg_ib_folder_already_exists"));
1497 g_object_unref (G_OBJECT (list));
1500 if (TNY_IS_FOLDER (parent)) {
1501 /* Check folder rules */
1502 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1503 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1504 /* Set status failed and set an error */
1505 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1506 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1507 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1508 _("mail_in_ui_folder_create_error"));
1512 if (!strcmp (name, " ") || strchr (name, '/')) {
1513 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1514 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1515 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1516 _("mail_in_ui_folder_create_error"));
1520 /* Create the folder */
1521 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1522 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1527 /* Notify about operation end */
1528 modest_mail_operation_notify_end (self);
1534 modest_mail_operation_remove_folder (ModestMailOperation *self,
1536 gboolean remove_to_trash)
1538 TnyAccount *account;
1539 ModestMailOperationPrivate *priv;
1540 ModestTnyFolderRules rules;
1542 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1543 g_return_if_fail (TNY_IS_FOLDER (folder));
1545 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1547 /* Check folder rules */
1548 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1549 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1550 /* Set status failed and set an error */
1551 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1552 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1553 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1554 _("mail_in_ui_folder_delete_error"));
1558 /* Get the account */
1559 account = modest_tny_folder_get_account (folder);
1560 priv->account = g_object_ref(account);
1562 /* Delete folder or move to trash */
1563 if (remove_to_trash) {
1564 TnyFolder *trash_folder = NULL;
1565 trash_folder = modest_tny_account_get_special_folder (account,
1566 TNY_FOLDER_TYPE_TRASH);
1567 /* TODO: error_handling */
1568 modest_mail_operation_xfer_folder (self, folder,
1569 TNY_FOLDER_STORE (trash_folder),
1572 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1574 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1575 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1578 g_object_unref (G_OBJECT (parent));
1580 g_object_unref (G_OBJECT (account));
1583 /* Notify about operation end */
1584 modest_mail_operation_notify_end (self);
1588 transfer_folder_status_cb (GObject *obj,
1592 ModestMailOperation *self;
1593 ModestMailOperationPrivate *priv;
1594 ModestMailOperationState *state;
1595 XFerMsgAsyncHelper *helper;
1597 g_return_if_fail (status != NULL);
1598 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1600 helper = (XFerMsgAsyncHelper *) user_data;
1601 g_return_if_fail (helper != NULL);
1603 self = helper->mail_op;
1604 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1606 priv->done = status->position;
1607 priv->total = status->of_total;
1609 state = modest_mail_operation_clone_state (self);
1610 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1611 g_slice_free (ModestMailOperationState, state);
1616 transfer_folder_cb (TnyFolder *folder,
1617 TnyFolderStore *into,
1619 TnyFolder *new_folder,
1623 XFerMsgAsyncHelper *helper;
1624 ModestMailOperation *self = NULL;
1625 ModestMailOperationPrivate *priv = NULL;
1627 helper = (XFerMsgAsyncHelper *) user_data;
1628 g_return_if_fail (helper != NULL);
1630 self = helper->mail_op;
1631 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1634 priv->error = g_error_copy (*err);
1636 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1637 } else if (cancelled) {
1638 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1639 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1640 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1641 _("Transference of %s was cancelled."),
1642 tny_folder_get_name (folder));
1645 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1648 /* Notify about operation end */
1649 modest_mail_operation_notify_end (self);
1651 /* If user defined callback function was defined, call it */
1652 if (helper->user_callback) {
1653 gdk_threads_enter ();
1654 helper->user_callback (priv->source, helper->user_data);
1655 gdk_threads_leave ();
1659 g_object_unref (helper->mail_op);
1660 g_slice_free (XFerMsgAsyncHelper, helper);
1664 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1666 TnyFolderStore *parent,
1667 gboolean delete_original,
1668 XferMsgsAsynUserCallback user_callback,
1671 ModestMailOperationPrivate *priv = NULL;
1672 ModestTnyFolderRules parent_rules = 0, rules;
1673 XFerMsgAsyncHelper *helper = NULL;
1675 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1676 g_return_if_fail (TNY_IS_FOLDER (folder));
1678 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1680 /* Get account and set it into mail_operation */
1681 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1682 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1684 /* Get folder rules */
1685 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1686 if (TNY_IS_FOLDER (parent))
1687 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1689 /* The moveable restriction is applied also to copy operation */
1690 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1691 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1692 /* Set status failed and set an error */
1693 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1694 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1695 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1696 _("mail_in_ui_folder_move_target_error"));
1698 /* Notify the queue */
1699 modest_mail_operation_notify_end (self);
1700 } else if (TNY_IS_FOLDER (parent) &&
1701 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1702 /* Set status failed and set an error */
1703 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1704 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1705 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1706 _("FIXME: parent folder does not accept new folders"));
1708 /* Notify the queue */
1709 modest_mail_operation_notify_end (self);
1711 /* Create the helper */
1712 helper = g_slice_new0 (XFerMsgAsyncHelper);
1713 helper->mail_op = g_object_ref(self);
1714 helper->dest_folder = NULL;
1715 helper->headers = NULL;
1716 helper->user_callback = user_callback;
1717 helper->user_data = user_data;
1719 /* Move/Copy folder */
1720 tny_folder_copy_async (folder,
1722 tny_folder_get_name (folder),
1725 transfer_folder_status_cb,
1732 modest_mail_operation_rename_folder (ModestMailOperation *self,
1736 ModestMailOperationPrivate *priv;
1737 ModestTnyFolderRules rules;
1738 XFerMsgAsyncHelper *helper;
1740 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1741 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1742 g_return_if_fail (name);
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1746 /* Get account and set it into mail_operation */
1747 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1749 /* Check folder rules */
1750 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1751 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1752 /* Set status failed and set an error */
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1755 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1756 _("FIXME: unable to rename"));
1758 /* Notify about operation end */
1759 modest_mail_operation_notify_end (self);
1760 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1761 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1762 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1763 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1764 _("FIXME: unable to rename"));
1765 /* Notify about operation end */
1766 modest_mail_operation_notify_end (self);
1768 TnyFolderStore *into;
1770 /* Create the helper */
1771 helper = g_slice_new0 (XFerMsgAsyncHelper);
1772 helper->mail_op = g_object_ref(self);
1773 helper->dest_folder = NULL;
1774 helper->headers = NULL;
1775 helper->user_callback = NULL;
1776 helper->user_data = NULL;
1778 /* Rename. Camel handles folder subscription/unsubscription */
1779 into = tny_folder_get_folder_store (folder);
1780 tny_folder_copy_async (folder, into, name, TRUE,
1782 transfer_folder_status_cb,
1786 g_object_unref (into);
1790 /* ******************************************************************* */
1791 /* ************************** MSG ACTIONS ************************* */
1792 /* ******************************************************************* */
1794 void modest_mail_operation_get_msg (ModestMailOperation *self,
1796 GetMsgAsyncUserCallback user_callback,
1799 GetMsgAsyncHelper *helper = NULL;
1801 ModestMailOperationPrivate *priv;
1803 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1804 g_return_if_fail (TNY_IS_HEADER (header));
1806 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1807 folder = tny_header_get_folder (header);
1809 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1811 /* Get message from folder */
1813 /* Get account and set it into mail_operation */
1814 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1816 helper = g_slice_new0 (GetMsgAsyncHelper);
1817 helper->mail_op = self;
1818 helper->user_callback = user_callback;
1819 helper->user_data = user_data;
1820 helper->header = g_object_ref (header);
1822 // The callback's reference so that the mail op is not
1823 // finalized until the async operation is completed even if
1824 // the user canceled the request meanwhile.
1825 g_object_ref (G_OBJECT (helper->mail_op));
1827 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1829 g_object_unref (G_OBJECT (folder));
1831 /* Set status failed and set an error */
1832 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1833 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1834 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1835 _("Error trying to get a message. No folder found for header"));
1837 /* Notify the queue */
1838 modest_mail_operation_notify_end (self);
1843 idle_get_mime_part_size_cb (gpointer userdata)
1845 GetMimePartSizeInfo *idle_info;
1847 idle_info = (GetMimePartSizeInfo *) userdata;
1849 gdk_threads_enter ();
1850 idle_info->callback (idle_info->mail_op,
1852 idle_info->userdata);
1853 gdk_threads_leave ();
1855 g_object_unref (idle_info->mail_op);
1856 g_slice_free (GetMimePartSizeInfo, idle_info);
1862 get_mime_part_size_thread (gpointer thr_user_data)
1864 GetMimePartSizeInfo *info;
1865 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1869 ModestMailOperationPrivate *priv;
1871 info = (GetMimePartSizeInfo *) thr_user_data;
1872 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1874 stream = tny_camel_mem_stream_new ();
1875 tny_mime_part_decode_to_stream (info->mime_part, stream);
1876 tny_stream_reset (stream);
1877 if (tny_stream_is_eos (stream)) {
1878 tny_stream_close (stream);
1879 stream = tny_mime_part_get_stream (info->mime_part);
1882 while (!tny_stream_is_eos (stream)) {
1883 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1884 total += readed_size;
1887 if (info->callback) {
1888 GetMimePartSizeInfo *idle_info;
1890 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1891 idle_info->mail_op = g_object_ref (info->mail_op);
1892 idle_info->size = total;
1893 idle_info->callback = info->callback;
1894 idle_info->userdata = info->userdata;
1895 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1898 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1900 g_object_unref (info->mail_op);
1901 g_object_unref (stream);
1902 g_object_unref (info->mime_part);
1903 g_slice_free (GetMimePartSizeInfo, info);
1909 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1911 GetMimePartSizeCallback user_callback,
1913 GDestroyNotify notify)
1915 GetMimePartSizeInfo *info;
1916 ModestMailOperationPrivate *priv;
1919 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1920 g_return_if_fail (TNY_IS_MIME_PART (part));
1922 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1924 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1925 info = g_slice_new0 (GetMimePartSizeInfo);
1926 info->mail_op = g_object_ref (self);
1927 info->mime_part = g_object_ref (part);
1928 info->callback = user_callback;
1929 info->userdata = user_data;
1931 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1936 get_msg_cb (TnyFolder *folder,
1942 GetMsgAsyncHelper *helper = NULL;
1943 ModestMailOperation *self = NULL;
1944 ModestMailOperationPrivate *priv = NULL;
1946 helper = (GetMsgAsyncHelper *) user_data;
1947 g_return_if_fail (helper != NULL);
1948 self = helper->mail_op;
1949 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1950 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1952 /* Check errors and cancel */
1954 priv->error = g_error_copy (*error);
1955 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1956 } else if (cancelled) {
1957 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1958 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1959 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1960 _("Error trying to refresh the contents of %s"),
1961 tny_folder_get_name (folder));
1963 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1966 /* If user defined callback function was defined, call it even
1967 if the operation failed*/
1968 if (helper->user_callback) {
1969 /* This callback is called into an iddle by tinymail,
1970 and idles are not in the main lock */
1971 gdk_threads_enter ();
1972 helper->user_callback (self, helper->header, msg, helper->user_data);
1973 gdk_threads_leave ();
1976 /* Notify about operation end */
1977 modest_mail_operation_notify_end (self);
1979 g_object_unref (helper->mail_op);
1980 g_object_unref (helper->header);
1981 g_slice_free (GetMsgAsyncHelper, helper);
1986 get_msg_status_cb (GObject *obj,
1990 GetMsgAsyncHelper *helper = NULL;
1991 ModestMailOperation *self;
1992 ModestMailOperationPrivate *priv;
1993 ModestMailOperationState *state;
1995 g_return_if_fail (status != NULL);
1996 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1998 helper = (GetMsgAsyncHelper *) user_data;
1999 g_return_if_fail (helper != NULL);
2001 self = helper->mail_op;
2002 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2004 if(priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED) {
2005 TnyFolder *folder = tny_header_get_folder (helper->header);
2007 TnyAccount *account;
2008 account = tny_folder_get_account (folder);
2010 tny_account_cancel (account);
2011 g_object_unref (account);
2013 g_object_unref (folder);
2022 state = modest_mail_operation_clone_state (self);
2023 state->bytes_done = status->position;
2024 state->bytes_total = status->of_total;
2025 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2026 g_slice_free (ModestMailOperationState, state);
2029 /****************************************************/
2031 ModestMailOperation *mail_op;
2033 GetMsgAsyncUserCallback user_callback;
2035 GDestroyNotify notify;
2039 GetMsgAsyncUserCallback user_callback;
2043 ModestMailOperation *mail_op;
2044 } NotifyGetMsgsInfo;
2048 * Used by get_msgs_full_thread to call the user_callback for each
2049 * message that has been read
2052 notify_get_msgs_full (gpointer data)
2054 NotifyGetMsgsInfo *info;
2056 info = (NotifyGetMsgsInfo *) data;
2058 /* Call the user callback. Idles are not in the main lock, so
2060 gdk_threads_enter ();
2061 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2062 gdk_threads_leave ();
2064 g_slice_free (NotifyGetMsgsInfo, info);
2070 * Used by get_msgs_full_thread to free al the thread resources and to
2071 * call the destroy function for the passed user_data
2074 get_msgs_full_destroyer (gpointer data)
2076 GetFullMsgsInfo *info;
2078 info = (GetFullMsgsInfo *) data;
2081 gdk_threads_enter ();
2082 info->notify (info->user_data);
2083 gdk_threads_leave ();
2087 g_object_unref (info->headers);
2088 g_slice_free (GetFullMsgsInfo, info);
2094 get_msgs_full_thread (gpointer thr_user_data)
2096 GetFullMsgsInfo *info;
2097 ModestMailOperationPrivate *priv = NULL;
2098 TnyIterator *iter = NULL;
2100 info = (GetFullMsgsInfo *) thr_user_data;
2101 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2103 iter = tny_list_create_iterator (info->headers);
2104 while (!tny_iterator_is_done (iter)) {
2108 header = TNY_HEADER (tny_iterator_get_current (iter));
2109 folder = tny_header_get_folder (header);
2111 /* Get message from folder */
2114 /* The callback will call it per each header */
2115 msg = tny_folder_get_msg (folder, header, &(priv->error));
2118 ModestMailOperationState *state;
2123 /* notify progress */
2124 state = modest_mail_operation_clone_state (info->mail_op);
2125 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2126 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2127 pair, (GDestroyNotify) modest_pair_free);
2129 /* The callback is the responsible for
2130 freeing the message */
2131 if (info->user_callback) {
2132 NotifyGetMsgsInfo *info_notify;
2133 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2134 info_notify->user_callback = info->user_callback;
2135 info_notify->mail_op = info->mail_op;
2136 info_notify->header = g_object_ref (header);
2137 info_notify->msg = g_object_ref (msg);
2138 info_notify->user_data = info->user_data;
2139 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2140 notify_get_msgs_full,
2143 g_object_unref (msg);
2146 /* Set status failed and set an error */
2147 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2148 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2149 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2150 "Error trying to get a message. No folder found for header");
2152 g_object_unref (header);
2153 tny_iterator_next (iter);
2156 /* Set operation status */
2157 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2158 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2160 /* Notify about operation end */
2161 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2163 /* Free thread resources. Will be called after all previous idles */
2164 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2170 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2171 TnyList *header_list,
2172 GetMsgAsyncUserCallback user_callback,
2174 GDestroyNotify notify)
2176 TnyHeader *header = NULL;
2177 TnyFolder *folder = NULL;
2179 ModestMailOperationPrivate *priv = NULL;
2180 GetFullMsgsInfo *info = NULL;
2181 gboolean size_ok = TRUE;
2183 TnyIterator *iter = NULL;
2185 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2187 /* Init mail operation */
2188 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2189 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2191 priv->total = tny_list_get_length(header_list);
2193 /* Get account and set it into mail_operation */
2194 if (tny_list_get_length (header_list) >= 1) {
2195 iter = tny_list_create_iterator (header_list);
2196 header = TNY_HEADER (tny_iterator_get_current (iter));
2197 folder = tny_header_get_folder (header);
2198 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2199 g_object_unref (header);
2200 g_object_unref (folder);
2202 if (tny_list_get_length (header_list) == 1) {
2203 g_object_unref (iter);
2208 /* Get msg size limit */
2209 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2210 MODEST_CONF_MSG_SIZE_LIMIT,
2213 g_clear_error (&(priv->error));
2214 max_size = G_MAXINT;
2216 max_size = max_size * KB;
2219 /* Check message size limits. If there is only one message
2220 always retrieve it */
2222 while (!tny_iterator_is_done (iter) && size_ok) {
2223 header = TNY_HEADER (tny_iterator_get_current (iter));
2224 if (tny_header_get_message_size (header) >= max_size)
2226 g_object_unref (header);
2227 tny_iterator_next (iter);
2229 g_object_unref (iter);
2233 /* Create the info */
2234 info = g_slice_new0 (GetFullMsgsInfo);
2235 info->mail_op = self;
2236 info->user_callback = user_callback;
2237 info->user_data = user_data;
2238 info->headers = g_object_ref (header_list);
2239 info->notify = notify;
2241 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2243 /* Set status failed and set an error */
2244 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2245 /* FIXME: the error msg is different for pop */
2246 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2247 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2248 _("emev_ni_ui_imap_msg_size_exceed_error"));
2249 /* Remove from queue and free resources */
2250 modest_mail_operation_notify_end (self);
2258 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2259 gboolean remove_to_trash /*ignored*/)
2262 ModestMailOperationPrivate *priv;
2264 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2265 g_return_if_fail (TNY_IS_HEADER (header));
2267 if (remove_to_trash)
2268 g_warning ("remove to trash is not implemented");
2270 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2271 folder = tny_header_get_folder (header);
2273 /* Get account and set it into mail_operation */
2274 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2276 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2279 tny_folder_remove_msg (folder, header, &(priv->error));
2281 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2282 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2284 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2285 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2286 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2287 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2290 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2296 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2298 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2301 g_object_unref (G_OBJECT (folder));
2303 /* Notify about operation end */
2304 modest_mail_operation_notify_end (self);
2308 transfer_msgs_status_cb (GObject *obj,
2312 XFerMsgAsyncHelper *helper = NULL;
2313 ModestMailOperation *self;
2314 ModestMailOperationPrivate *priv;
2315 ModestMailOperationState *state;
2318 g_return_if_fail (status != NULL);
2319 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2321 helper = (XFerMsgAsyncHelper *) user_data;
2322 g_return_if_fail (helper != NULL);
2324 self = helper->mail_op;
2325 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2327 priv->done = status->position;
2328 priv->total = status->of_total;
2330 state = modest_mail_operation_clone_state (self);
2331 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2332 g_slice_free (ModestMailOperationState, state);
2337 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2339 XFerMsgAsyncHelper *helper;
2340 ModestMailOperation *self;
2341 ModestMailOperationPrivate *priv;
2343 helper = (XFerMsgAsyncHelper *) user_data;
2344 self = helper->mail_op;
2346 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2349 priv->error = g_error_copy (*err);
2351 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2352 } else if (cancelled) {
2353 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2354 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2355 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2356 _("Error trying to refresh the contents of %s"),
2357 tny_folder_get_name (folder));
2360 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2363 /* Notify about operation end */
2364 modest_mail_operation_notify_end (self);
2366 /* If user defined callback function was defined, call it */
2367 if (helper->user_callback) {
2368 gdk_threads_enter ();
2369 helper->user_callback (priv->source, helper->user_data);
2370 gdk_threads_leave ();
2374 g_object_unref (helper->headers);
2375 g_object_unref (helper->dest_folder);
2376 g_object_unref (helper->mail_op);
2377 g_slice_free (XFerMsgAsyncHelper, helper);
2378 g_object_unref (folder);
2383 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2386 gboolean delete_original,
2387 XferMsgsAsynUserCallback user_callback,
2390 ModestMailOperationPrivate *priv;
2392 TnyFolder *src_folder;
2393 XFerMsgAsyncHelper *helper;
2395 ModestTnyFolderRules rules;
2396 const gchar *id1 = NULL;
2397 const gchar *id2 = NULL;
2398 gboolean same_folder = FALSE;
2400 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2401 g_return_if_fail (TNY_IS_LIST (headers));
2402 g_return_if_fail (TNY_IS_FOLDER (folder));
2404 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2407 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2409 /* Apply folder rules */
2410 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2411 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2412 /* Set status failed and set an error */
2413 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2414 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2415 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2416 _CS("ckct_ib_unable_to_paste_here"));
2417 /* Notify the queue */
2418 modest_mail_operation_notify_end (self);
2422 /* Get source folder */
2423 iter = tny_list_create_iterator (headers);
2424 header = TNY_HEADER (tny_iterator_get_current (iter));
2425 src_folder = tny_header_get_folder (header);
2426 g_object_unref (header);
2427 g_object_unref (iter);
2429 /* Check folder source and destination */
2430 id1 = tny_folder_get_id (src_folder);
2431 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2432 same_folder = !g_ascii_strcasecmp (id1, id2);
2434 /* Set status failed and set an error */
2435 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2436 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2437 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2438 _("mcen_ib_unable_to_copy_samefolder"));
2440 /* Notify the queue */
2441 modest_mail_operation_notify_end (self);
2444 g_object_unref (src_folder);
2448 /* Create the helper */
2449 helper = g_slice_new0 (XFerMsgAsyncHelper);
2450 helper->mail_op = g_object_ref(self);
2451 helper->dest_folder = g_object_ref(folder);
2452 helper->headers = g_object_ref(headers);
2453 helper->user_callback = user_callback;
2454 helper->user_data = user_data;
2456 /* Get account and set it into mail_operation */
2457 priv->account = modest_tny_folder_get_account (src_folder);
2459 /* Transfer messages */
2460 tny_folder_transfer_msgs_async (src_folder,
2465 transfer_msgs_status_cb,
2471 on_refresh_folder (TnyFolder *folder,
2476 RefreshAsyncHelper *helper = NULL;
2477 ModestMailOperation *self = NULL;
2478 ModestMailOperationPrivate *priv = NULL;
2480 helper = (RefreshAsyncHelper *) user_data;
2481 self = helper->mail_op;
2482 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2485 priv->error = g_error_copy (*error);
2486 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2491 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2492 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2493 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2494 _("Error trying to refresh the contents of %s"),
2495 tny_folder_get_name (folder));
2499 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2501 /* Call user defined callback, if it exists */
2502 if (helper->user_callback) {
2503 gdk_threads_enter ();
2504 helper->user_callback (self, folder, helper->user_data);
2505 gdk_threads_leave ();
2509 g_object_unref (helper->mail_op);
2510 g_slice_free (RefreshAsyncHelper, helper);
2512 /* Notify about operation end */
2513 modest_mail_operation_notify_end (self);
2517 on_refresh_folder_status_update (GObject *obj,
2521 RefreshAsyncHelper *helper = NULL;
2522 ModestMailOperation *self = NULL;
2523 ModestMailOperationPrivate *priv = NULL;
2524 ModestMailOperationState *state;
2526 g_return_if_fail (user_data != NULL);
2527 g_return_if_fail (status != NULL);
2528 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2530 helper = (RefreshAsyncHelper *) user_data;
2531 self = helper->mail_op;
2532 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2534 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2536 priv->done = status->position;
2537 priv->total = status->of_total;
2539 state = modest_mail_operation_clone_state (self);
2540 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2541 g_slice_free (ModestMailOperationState, state);
2545 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2547 RefreshAsyncUserCallback user_callback,
2550 ModestMailOperationPrivate *priv = NULL;
2551 RefreshAsyncHelper *helper = NULL;
2553 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2555 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2557 /* Get account and set it into mail_operation */
2558 priv->account = modest_tny_folder_get_account (folder);
2560 /* Create the helper */
2561 helper = g_slice_new0 (RefreshAsyncHelper);
2562 helper->mail_op = g_object_ref(self);
2563 helper->user_callback = user_callback;
2564 helper->user_data = user_data;
2566 /* Refresh the folder. TODO: tinymail could issue a status
2567 updates before the callback call then this could happen. We
2568 must review the design */
2569 tny_folder_refresh_async (folder,
2571 on_refresh_folder_status_update,
2577 * It's used by the mail operation queue to notify the observers
2578 * attached to that signal that the operation finished. We need to use
2579 * that because tinymail does not give us the progress of a given
2580 * operation when it finishes (it directly calls the operation
2584 modest_mail_operation_notify_end (ModestMailOperation *self)
2586 ModestMailOperationState *state;
2587 ModestMailOperationPrivate *priv = NULL;
2589 g_return_if_fail (self);
2591 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2593 /* Set the account back to not busy */
2594 if (priv->account_name) {
2595 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2596 priv->account_name, FALSE);
2597 g_free(priv->account_name);
2598 priv->account_name = NULL;
2601 /* Notify the observers about the mail opertation end */
2602 state = modest_mail_operation_clone_state (self);
2603 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2604 g_slice_free (ModestMailOperationState, state);