1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <tny-mime-part.h>
33 #include <tny-store-account.h>
34 #include <tny-folder-store.h>
35 #include <tny-folder-store-query.h>
36 #include <tny-camel-stream.h>
37 #include <tny-camel-pop-store-account.h>
38 #include <tny-camel-pop-folder.h>
39 #include <tny-camel-imap-folder.h>
40 #include <tny-camel-mem-stream.h>
41 #include <tny-simple-list.h>
42 #include <tny-send-queue.h>
43 #include <tny-status.h>
44 #include <tny-folder-observer.h>
45 #include <camel/camel-stream-mem.h>
46 #include <glib/gi18n.h>
47 #include "modest-platform.h"
48 #include <modest-tny-account.h>
49 #include <modest-tny-send-queue.h>
50 #include <modest-runtime.h>
51 #include "modest-text-utils.h"
52 #include "modest-tny-msg.h"
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account-store.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-marshal.h"
57 #include "modest-error.h"
58 #include "modest-mail-operation.h"
61 #define GET_SIZE_BUFFER_SIZE 128
64 * Remove all these #ifdef stuff when the tinymail's idle calls become
67 #define TINYMAIL_IDLES_NOT_LOCKED_YET 1
69 /* 'private'/'protected' functions */
70 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
71 static void modest_mail_operation_init (ModestMailOperation *obj);
72 static void modest_mail_operation_finalize (GObject *obj);
74 static void get_msg_cb (TnyFolder *folder,
80 static void get_msg_status_cb (GObject *obj,
84 static void modest_mail_operation_notify_end (ModestMailOperation *self);
86 enum _ModestMailOperationSignals
88 PROGRESS_CHANGED_SIGNAL,
93 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
94 struct _ModestMailOperationPrivate {
101 ErrorCheckingUserCallback error_checking;
102 gpointer error_checking_user_data;
103 ModestMailOperationStatus status;
104 ModestMailOperationTypeOperation op_type;
107 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
108 MODEST_TYPE_MAIL_OPERATION, \
109 ModestMailOperationPrivate))
111 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
112 priv->status = new_status;\
115 typedef struct _GetMsgAsyncHelper {
116 ModestMailOperation *mail_op;
118 GetMsgAsyncUserCallback user_callback;
122 typedef struct _RefreshAsyncHelper {
123 ModestMailOperation *mail_op;
124 RefreshAsyncUserCallback user_callback;
126 } RefreshAsyncHelper;
128 typedef struct _XFerMsgAsyncHelper
130 ModestMailOperation *mail_op;
132 TnyFolder *dest_folder;
133 XferMsgsAsynUserCallback user_callback;
135 } XFerMsgAsyncHelper;
137 typedef void (*ModestMailOperationCreateMsgCallback) (ModestMailOperation *mail_op,
141 static void modest_mail_operation_create_msg (ModestMailOperation *self,
142 const gchar *from, const gchar *to,
143 const gchar *cc, const gchar *bcc,
144 const gchar *subject, const gchar *plain_body,
145 const gchar *html_body, const GList *attachments_list,
146 TnyHeaderFlags priority_flags,
147 ModestMailOperationCreateMsgCallback callback,
150 static gboolean idle_notify_queue (gpointer data);
153 ModestMailOperation *mail_op;
161 GList *attachments_list;
162 TnyHeaderFlags priority_flags;
163 ModestMailOperationCreateMsgCallback callback;
169 ModestMailOperation *mail_op;
171 ModestMailOperationCreateMsgCallback callback;
176 static GObjectClass *parent_class = NULL;
178 static guint signals[NUM_SIGNALS] = {0};
181 modest_mail_operation_get_type (void)
183 static GType my_type = 0;
185 static const GTypeInfo my_info = {
186 sizeof(ModestMailOperationClass),
187 NULL, /* base init */
188 NULL, /* base finalize */
189 (GClassInitFunc) modest_mail_operation_class_init,
190 NULL, /* class finalize */
191 NULL, /* class data */
192 sizeof(ModestMailOperation),
194 (GInstanceInitFunc) modest_mail_operation_init,
197 my_type = g_type_register_static (G_TYPE_OBJECT,
198 "ModestMailOperation",
205 modest_mail_operation_class_init (ModestMailOperationClass *klass)
207 GObjectClass *gobject_class;
208 gobject_class = (GObjectClass*) klass;
210 parent_class = g_type_class_peek_parent (klass);
211 gobject_class->finalize = modest_mail_operation_finalize;
213 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
216 * ModestMailOperation::progress-changed
217 * @self: the #MailOperation that emits the signal
218 * @user_data: user data set when the signal handler was connected
220 * Emitted when the progress of a mail operation changes
222 signals[PROGRESS_CHANGED_SIGNAL] =
223 g_signal_new ("progress-changed",
224 G_TYPE_FROM_CLASS (gobject_class),
226 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
228 g_cclosure_marshal_VOID__POINTER,
229 G_TYPE_NONE, 1, G_TYPE_POINTER);
234 modest_mail_operation_init (ModestMailOperation *obj)
236 ModestMailOperationPrivate *priv;
238 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
240 priv->account = NULL;
241 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
242 priv->op_type = MODEST_MAIL_OPERATION_TYPE_UNKNOWN;
247 priv->error_checking = NULL;
248 priv->error_checking_user_data = NULL;
252 modest_mail_operation_finalize (GObject *obj)
254 ModestMailOperationPrivate *priv;
256 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
261 g_error_free (priv->error);
265 g_object_unref (priv->source);
269 g_object_unref (priv->account);
270 priv->account = NULL;
274 G_OBJECT_CLASS(parent_class)->finalize (obj);
278 modest_mail_operation_new (ModestMailOperationTypeOperation op_type,
281 ModestMailOperation *obj;
282 ModestMailOperationPrivate *priv;
284 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
285 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
287 priv->op_type = op_type;
289 priv->source = g_object_ref(source);
295 modest_mail_operation_new_with_error_handling (ModestMailOperationTypeOperation op_type,
297 ErrorCheckingUserCallback error_handler,
300 ModestMailOperation *obj;
301 ModestMailOperationPrivate *priv;
303 obj = modest_mail_operation_new (op_type, source);
304 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
306 g_return_val_if_fail (error_handler != NULL, obj);
307 priv->error_checking = error_handler;
313 modest_mail_operation_execute_error_handler (ModestMailOperation *self)
315 ModestMailOperationPrivate *priv;
317 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
318 g_return_if_fail(priv->status != MODEST_MAIL_OPERATION_STATUS_SUCCESS);
320 if (priv->error_checking != NULL)
321 priv->error_checking (self, priv->error_checking_user_data);
325 ModestMailOperationTypeOperation
326 modest_mail_operation_get_type_operation (ModestMailOperation *self)
328 ModestMailOperationPrivate *priv;
330 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
332 return priv->op_type;
336 modest_mail_operation_is_mine (ModestMailOperation *self,
339 ModestMailOperationPrivate *priv;
341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
342 if (priv->source == NULL) return FALSE;
344 return priv->source == me;
348 modest_mail_operation_get_source (ModestMailOperation *self)
350 ModestMailOperationPrivate *priv;
352 g_return_val_if_fail (self, NULL);
354 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
356 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
360 return g_object_ref (priv->source);
363 ModestMailOperationStatus
364 modest_mail_operation_get_status (ModestMailOperation *self)
366 ModestMailOperationPrivate *priv;
368 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
369 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
370 MODEST_MAIL_OPERATION_STATUS_INVALID);
372 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
374 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
375 return MODEST_MAIL_OPERATION_STATUS_INVALID;
382 modest_mail_operation_get_error (ModestMailOperation *self)
384 ModestMailOperationPrivate *priv;
386 g_return_val_if_fail (self, NULL);
387 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
389 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
392 g_warning ("BUG: %s: priv == NULL", __FUNCTION__);
400 modest_mail_operation_cancel (ModestMailOperation *self)
402 ModestMailOperationPrivate *priv;
403 gboolean canceled = FALSE;
405 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
409 /* Note that if we call cancel with an already canceled mail
410 operation the progress changed signal won't be emitted */
411 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
415 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
417 /* Cancel the mail operation. We need to wrap it between this
418 start/stop operations to allow following calls to the
421 tny_account_cancel (priv->account);
427 modest_mail_operation_get_task_done (ModestMailOperation *self)
429 ModestMailOperationPrivate *priv;
431 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
433 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
438 modest_mail_operation_get_task_total (ModestMailOperation *self)
440 ModestMailOperationPrivate *priv;
442 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
449 modest_mail_operation_is_finished (ModestMailOperation *self)
451 ModestMailOperationPrivate *priv;
452 gboolean retval = FALSE;
454 if (!MODEST_IS_MAIL_OPERATION (self)) {
455 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
459 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
461 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
464 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
474 modest_mail_operation_get_id (ModestMailOperation *self)
476 ModestMailOperationPrivate *priv;
478 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
485 modest_mail_operation_set_id (ModestMailOperation *self,
488 ModestMailOperationPrivate *priv;
490 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
492 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
497 * Creates an image of the current state of a mail operation, the
498 * caller must free it
500 static ModestMailOperationState *
501 modest_mail_operation_clone_state (ModestMailOperation *self)
503 ModestMailOperationState *state;
504 ModestMailOperationPrivate *priv;
506 /* FIXME: this should be fixed properly
508 * in some cases, priv was NULL, so checking here to
511 g_return_val_if_fail (self, NULL);
512 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
513 g_return_val_if_fail (priv, NULL);
518 state = g_slice_new (ModestMailOperationState);
520 state->status = priv->status;
521 state->op_type = priv->op_type;
522 state->done = priv->done;
523 state->total = priv->total;
524 state->finished = modest_mail_operation_is_finished (self);
525 state->bytes_done = 0;
526 state->bytes_total = 0;
531 /* ******************************************************************* */
532 /* ************************** SEND ACTIONS ************************* */
533 /* ******************************************************************* */
536 modest_mail_operation_send_mail (ModestMailOperation *self,
537 TnyTransportAccount *transport_account,
540 TnySendQueue *send_queue = NULL;
541 ModestMailOperationPrivate *priv;
543 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
544 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
545 g_return_if_fail (TNY_IS_MSG (msg));
547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
549 /* Get account and set it into mail_operation */
550 priv->account = g_object_ref (transport_account);
554 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
555 if (!TNY_IS_SEND_QUEUE(send_queue)) {
556 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
557 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
558 "modest: could not find send queue for account\n");
560 /* TODO: connect to the msg-sent in order to know when
561 the mail operation is finished */
562 tny_send_queue_add (send_queue, msg, &(priv->error));
563 /* TODO: we're setting always success, do the check in
565 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
568 /* TODO: do this in the handler of the "msg-sent"
569 signal.Notify about operation end */
570 modest_mail_operation_notify_end (self);
574 idle_create_msg_cb (gpointer idle_data)
576 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
578 gdk_threads_enter ();
579 info->callback (info->mail_op, info->msg, info->userdata);
580 gdk_threads_leave ();
581 g_object_unref (info->mail_op);
583 g_object_unref (info->msg);
584 g_slice_free (CreateMsgIdleInfo, info);
590 create_msg_thread (gpointer thread_data)
592 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
593 TnyMsg *new_msg = NULL;
594 ModestMailOperationPrivate *priv;
596 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
597 if (info->html_body == NULL) {
598 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
599 info->bcc, info->subject, info->plain_body,
600 info->attachments_list); /* FIXME: attachments */
602 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
603 info->bcc, info->subject, info->html_body,
604 info->plain_body, info->attachments_list);
609 /* Set priority flags in message */
610 header = tny_msg_get_header (new_msg);
611 if (info->priority_flags != 0)
612 tny_header_set_flags (header, info->priority_flags);
613 if (info->attachments_list != NULL) {
614 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
616 g_object_unref (G_OBJECT(header));
618 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
619 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
620 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
621 "modest: failed to create a new msg\n");
629 g_free (info->plain_body);
630 g_free (info->html_body);
631 g_free (info->subject);
632 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
633 g_list_free (info->attachments_list);
635 if (info->callback) {
636 CreateMsgIdleInfo *idle_info;
637 idle_info = g_slice_new0 (CreateMsgIdleInfo);
638 idle_info->mail_op = info->mail_op;
639 g_object_ref (info->mail_op);
640 idle_info->msg = new_msg;
642 g_object_ref (new_msg);
643 idle_info->callback = info->callback;
644 idle_info->userdata = info->userdata;
645 g_idle_add (idle_create_msg_cb, idle_info);
647 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
650 g_object_unref (info->mail_op);
651 g_slice_free (CreateMsgInfo, info);
656 modest_mail_operation_create_msg (ModestMailOperation *self,
657 const gchar *from, const gchar *to,
658 const gchar *cc, const gchar *bcc,
659 const gchar *subject, const gchar *plain_body,
660 const gchar *html_body,
661 const GList *attachments_list,
662 TnyHeaderFlags priority_flags,
663 ModestMailOperationCreateMsgCallback callback,
666 CreateMsgInfo *info = NULL;
668 info = g_slice_new0 (CreateMsgInfo);
669 info->mail_op = self;
672 info->from = g_strdup (from);
673 info->to = g_strdup (to);
674 info->cc = g_strdup (cc);
675 info->subject = g_strdup (subject);
676 info->plain_body = g_strdup (plain_body);
677 info->html_body = g_strdup (html_body);
678 info->attachments_list = g_list_copy ((GList *) attachments_list);
679 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
680 info->priority_flags = priority_flags;
682 info->callback = callback;
683 info->userdata = userdata;
685 g_thread_create (create_msg_thread, info, FALSE, NULL);
690 TnyTransportAccount *transport_account;
695 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
699 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
707 /* Call mail operation */
708 modest_mail_operation_send_mail (self, info->transport_account, msg);
710 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
712 if (info->draft_msg != NULL) {
713 header = tny_msg_get_header (info->draft_msg);
714 /* Note: This can fail (with a warning) if the message is not really already in a folder,
715 * because this function requires it to have a UID. */
716 tny_folder_remove_msg (folder, header, NULL);
717 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
718 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
719 g_object_unref (header);
720 g_object_unref (folder);
726 g_object_unref (info->draft_msg);
727 if (info->transport_account)
728 g_object_unref (info->transport_account);
729 g_slice_free (SendNewMailInfo, info);
730 modest_mail_operation_notify_end (self);
734 modest_mail_operation_send_new_mail (ModestMailOperation *self,
735 TnyTransportAccount *transport_account,
737 const gchar *from, const gchar *to,
738 const gchar *cc, const gchar *bcc,
739 const gchar *subject, const gchar *plain_body,
740 const gchar *html_body,
741 const GList *attachments_list,
742 TnyHeaderFlags priority_flags)
744 ModestMailOperationPrivate *priv = NULL;
745 SendNewMailInfo *info;
747 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
748 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
750 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
752 /* Check parametters */
754 /* Set status failed and set an error */
755 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
756 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
757 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
758 _("Error trying to send a mail. You need to set at least one recipient"));
761 info = g_slice_new0 (SendNewMailInfo);
762 info->transport_account = transport_account;
763 if (transport_account)
764 g_object_ref (transport_account);
765 info->draft_msg = draft_msg;
767 g_object_ref (draft_msg);
768 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
769 attachments_list, priority_flags,
770 modest_mail_operation_send_new_mail_cb, info);
776 TnyTransportAccount *transport_account;
778 ModestMsgEditWindow *edit_window;
782 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
786 TnyFolder *folder = NULL;
787 TnyHeader *header = NULL;
788 ModestMailOperationPrivate *priv = NULL;
789 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
791 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
793 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
794 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
795 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
796 "modest: failed to create a new msg\n");
800 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
802 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
803 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
804 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
805 "modest: failed to create a new msg\n");
809 if (info->draft_msg != NULL) {
810 header = tny_msg_get_header (info->draft_msg);
811 /* Remove the old draft expunging it */
812 tny_folder_remove_msg (folder, header, NULL);
813 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
814 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
815 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
816 g_object_unref (header);
820 tny_folder_add_msg (folder, msg, &(priv->error));
823 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
825 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
827 if (info->edit_window)
828 modest_msg_edit_window_set_draft (info->edit_window, msg);
833 g_object_unref (G_OBJECT(folder));
834 if (info->edit_window)
835 g_object_unref (G_OBJECT(info->edit_window));
837 g_object_unref (G_OBJECT (info->draft_msg));
838 if (info->transport_account)
839 g_object_unref (G_OBJECT(info->transport_account));
840 g_slice_free (SaveToDraftsInfo, info);
842 modest_mail_operation_notify_end (self);
846 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
847 TnyTransportAccount *transport_account,
849 ModestMsgEditWindow *edit_window,
850 const gchar *from, const gchar *to,
851 const gchar *cc, const gchar *bcc,
852 const gchar *subject, const gchar *plain_body,
853 const gchar *html_body,
854 const GList *attachments_list,
855 TnyHeaderFlags priority_flags)
857 ModestMailOperationPrivate *priv = NULL;
858 SaveToDraftsInfo *info = NULL;
860 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
861 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
863 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
865 /* Get account and set it into mail_operation */
866 priv->account = g_object_ref (transport_account);
868 info = g_slice_new0 (SaveToDraftsInfo);
869 info->transport_account = g_object_ref (transport_account);
870 info->draft_msg = draft_msg;
872 g_object_ref (draft_msg);
873 info->edit_window = edit_window;
875 g_object_ref (edit_window);
877 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
878 attachments_list, priority_flags,
879 modest_mail_operation_save_to_drafts_cb, info);
885 ModestMailOperation *mail_op;
886 TnyStoreAccount *account;
887 TnyTransportAccount *transport_account;
890 gchar *retrieve_type;
892 UpdateAccountCallback callback;
899 ModestMailOperation *mail_op;
900 TnyMimePart *mime_part;
902 GetMimePartSizeCallback callback;
904 } GetMimePartSizeInfo;
906 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
907 /* We use this folder observer to track the headers that have been
908 * added to a folder */
911 TnyList *new_headers;
912 } InternalFolderObserver;
916 } InternalFolderObserverClass;
918 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
920 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
921 internal_folder_observer,
923 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
927 foreach_add_item (gpointer header, gpointer user_data)
929 tny_list_prepend (TNY_LIST (user_data),
930 g_object_ref (G_OBJECT (header)));
933 /* This is the method that looks for new messages in a folder */
935 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
937 InternalFolderObserver *derived = (InternalFolderObserver *)self;
939 TnyFolderChangeChanged changed;
941 changed = tny_folder_change_get_changed (change);
943 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
946 /* Get added headers */
947 list = tny_simple_list_new ();
948 tny_folder_change_get_added_headers (change, list);
950 /* Add them to the folder observer */
951 tny_list_foreach (list, foreach_add_item,
952 derived->new_headers);
954 g_object_unref (G_OBJECT (list));
959 internal_folder_observer_init (InternalFolderObserver *self)
961 self->new_headers = tny_simple_list_new ();
964 internal_folder_observer_finalize (GObject *object)
966 InternalFolderObserver *self;
968 self = (InternalFolderObserver *) object;
969 g_object_unref (self->new_headers);
971 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
974 tny_folder_observer_init (TnyFolderObserverIface *iface)
976 iface->update_func = internal_folder_observer_update;
979 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
981 GObjectClass *object_class;
983 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
984 object_class = (GObjectClass*) klass;
985 object_class->finalize = internal_folder_observer_finalize;
991 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
994 TnyList *folders = tny_simple_list_new ();
996 tny_folder_store_get_folders (store, folders, query, NULL);
997 iter = tny_list_create_iterator (folders);
999 while (!tny_iterator_is_done (iter)) {
1001 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1003 tny_list_prepend (all_folders, G_OBJECT (folder));
1004 recurse_folders (folder, query, all_folders);
1005 g_object_unref (G_OBJECT (folder));
1007 tny_iterator_next (iter);
1009 g_object_unref (G_OBJECT (iter));
1010 g_object_unref (G_OBJECT (folders));
1014 * Issues the "progress-changed" signal. The timer won't be removed,
1015 * so you must call g_source_remove to stop the signal emission
1018 idle_notify_progress (gpointer data)
1020 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1021 ModestMailOperationState *state;
1023 state = modest_mail_operation_clone_state (mail_op);
1024 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1025 gdk_threads_enter ();
1027 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1028 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1029 gdk_threads_leave ();
1031 g_slice_free (ModestMailOperationState, state);
1037 * Issues the "progress-changed" signal and removes the timer. It uses
1038 * a lock to ensure that the progress information of the mail
1039 * operation is not modified while there are notifications pending
1042 idle_notify_progress_once (gpointer data)
1046 pair = (ModestPair *) data;
1048 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1049 gdk_threads_enter ();
1051 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1052 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1053 gdk_threads_leave ();
1056 /* Free the state and the reference to the mail operation */
1057 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1058 g_object_unref (pair->first);
1064 * Used to notify the queue from the main
1065 * loop. We call it inside an idle call to achieve that
1068 idle_notify_queue (gpointer data)
1070 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1072 /* Do not need to block, the notify end will do it for us */
1073 modest_mail_operation_notify_end (mail_op);
1074 g_object_unref (mail_op);
1080 compare_headers_by_date (gconstpointer a,
1083 TnyHeader **header1, **header2;
1084 time_t sent1, sent2;
1086 header1 = (TnyHeader **) a;
1087 header2 = (TnyHeader **) b;
1089 sent1 = tny_header_get_date_sent (*header1);
1090 sent2 = tny_header_get_date_sent (*header2);
1092 /* We want the most recent ones (greater time_t) at the
1101 set_last_updated_idle (gpointer data)
1103 gdk_threads_enter ();
1105 /* It does not matter if the time is not exactly the same than
1106 the time when this idle was called, it's just an
1107 approximation and it won't be very different */
1108 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1110 MODEST_ACCOUNT_LAST_UPDATED,
1114 gdk_threads_leave ();
1120 idle_update_account_cb (gpointer data)
1122 UpdateAccountInfo *idle_info;
1124 idle_info = (UpdateAccountInfo *) data;
1126 gdk_threads_enter ();
1127 idle_info->callback (idle_info->mail_op,
1128 idle_info->new_headers,
1129 idle_info->user_data);
1130 gdk_threads_leave ();
1133 g_object_unref (idle_info->mail_op);
1141 update_account_thread (gpointer thr_user_data)
1143 static gboolean first_time = TRUE;
1144 UpdateAccountInfo *info = NULL;
1145 TnyList *all_folders = NULL;
1146 GPtrArray *new_headers = NULL;
1147 TnyIterator *iter = NULL;
1148 TnyFolderStoreQuery *query = NULL;
1149 ModestMailOperationPrivate *priv = NULL;
1150 ModestTnySendQueue *send_queue = NULL;
1151 gint num_new_headers = 0;
1153 info = (UpdateAccountInfo *) thr_user_data;
1154 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1156 /* Get account and set it into mail_operation */
1157 priv->account = g_object_ref (info->account);
1160 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1161 * show any updates unless we do that
1163 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1164 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1166 /* Get all the folders. We can do it synchronously because
1167 we're already running in a different thread than the UI */
1168 all_folders = tny_simple_list_new ();
1169 query = tny_folder_store_query_new ();
1170 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1171 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1176 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1180 iter = tny_list_create_iterator (all_folders);
1181 while (!tny_iterator_is_done (iter)) {
1182 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1184 recurse_folders (folder, query, all_folders);
1185 tny_iterator_next (iter);
1187 g_object_unref (G_OBJECT (iter));
1189 /* Update status and notify. We need to call the notification
1190 with a source function in order to call it from the main
1191 loop. We need that in order not to get into trouble with
1192 Gtk+. We use a timeout in order to provide more status
1193 information, because the sync tinymail call does not
1194 provide it for the moment */
1195 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1197 /* Refresh folders */
1198 num_new_headers = 0;
1199 new_headers = g_ptr_array_new ();
1200 iter = tny_list_create_iterator (all_folders);
1202 while (!tny_iterator_is_done (iter) && !priv->error &&
1203 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1205 InternalFolderObserver *observer;
1206 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1208 /* Refresh the folder */
1209 /* Our observer receives notification of new emails during folder refreshes,
1210 * so we can use observer->new_headers.
1212 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1213 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1215 /* This gets the status information (headers) from the server.
1216 * We use the blocking version, because we are already in a separate
1220 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1221 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1224 /* If the retrieve type is full messages, refresh and get the messages */
1225 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1227 iter = tny_list_create_iterator (observer->new_headers);
1228 while (!tny_iterator_is_done (iter)) {
1229 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1231 /* Apply per-message size limits */
1232 if (tny_header_get_message_size (header) < info->max_size)
1233 g_ptr_array_add (new_headers, g_object_ref (header));
1235 g_object_unref (header);
1236 tny_iterator_next (iter);
1238 g_object_unref (iter);
1240 /* We do not need to do it the first time
1241 because it's automatically done by the tree
1243 if (G_UNLIKELY (!first_time))
1244 tny_folder_poke_status (TNY_FOLDER (folder));
1246 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1247 g_object_unref (observer);
1250 g_object_unref (G_OBJECT (folder));
1252 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1254 tny_iterator_next (iter);
1257 g_object_unref (G_OBJECT (iter));
1258 g_source_remove (timeout);
1260 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1261 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1262 new_headers->len > 0) {
1266 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1268 /* Apply message count limit */
1269 /* If the number of messages exceeds the maximum, ask the
1270 * user to download them all,
1271 * as per the UI spec "Retrieval Limits" section in 4.4:
1273 if (new_headers->len > info->retrieve_limit) {
1274 /* TODO: Ask the user, instead of just
1276 * mail_nc_msg_count_limit_exceeded, with 'Get
1277 * all' and 'Newest only' buttons. */
1278 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1279 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1280 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1281 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1282 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1287 priv->total = MIN (new_headers->len, info->retrieve_limit);
1288 while (msg_num < priv->total) {
1290 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1291 TnyFolder *folder = tny_header_get_folder (header);
1292 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1293 ModestMailOperationState *state;
1297 /* We can not just use the mail operation because the
1298 values of done and total could change before the
1300 state = modest_mail_operation_clone_state (info->mail_op);
1301 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1302 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1303 pair, (GDestroyNotify) modest_pair_free);
1305 g_object_unref (msg);
1306 g_object_unref (folder);
1312 /* Get the number of new headers and free them */
1313 num_new_headers = new_headers->len;
1314 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1315 g_ptr_array_free (new_headers, FALSE);
1317 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1320 /* Perform send (if operation was not cancelled) */
1321 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1324 if (priv->account != NULL)
1325 g_object_unref (priv->account);
1326 priv->account = g_object_ref (info->transport_account);
1328 send_queue = modest_runtime_get_send_queue (info->transport_account);
1330 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1331 modest_tny_send_queue_try_to_send (send_queue);
1332 /* g_source_remove (timeout); */
1334 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1335 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1336 "cannot create a send queue for %s\n",
1337 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1338 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1341 /* Check if the operation was a success */
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1345 /* Update the last updated key */
1346 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1347 set_last_updated_idle,
1348 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1349 (GDestroyNotify) g_free);
1354 if (info->callback) {
1355 UpdateAccountInfo *idle_info;
1357 /* This thread is not in the main lock */
1358 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1359 idle_info->mail_op = g_object_ref (info->mail_op);
1360 idle_info->new_headers = num_new_headers;
1361 idle_info->callback = info->callback;
1362 g_idle_add (idle_update_account_cb, idle_info);
1365 /* Notify about operation end. Note that the info could be
1366 freed before this idle happens, but the mail operation will
1368 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1371 g_object_unref (query);
1372 g_object_unref (all_folders);
1373 g_object_unref (info->account);
1374 g_object_unref (info->transport_account);
1375 g_free (info->retrieve_type);
1376 g_slice_free (UpdateAccountInfo, info);
1384 modest_mail_operation_update_account (ModestMailOperation *self,
1385 const gchar *account_name,
1386 UpdateAccountCallback callback,
1389 GThread *thread = NULL;
1390 UpdateAccountInfo *info = NULL;
1391 ModestMailOperationPrivate *priv = NULL;
1392 ModestAccountMgr *mgr = NULL;
1393 TnyStoreAccount *store_account = NULL;
1394 TnyTransportAccount *transport_account = NULL;
1396 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1397 g_return_val_if_fail (account_name, FALSE);
1399 /* Init mail operation. Set total and done to 0, and do not
1400 update them, this way the progress objects will know that
1401 we have no clue about the number of the objects */
1402 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1405 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1407 /* Get the Modest account */
1408 store_account = (TnyStoreAccount *)
1409 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1411 TNY_ACCOUNT_TYPE_STORE);
1413 /* Make sure that we have a connection, and request one
1415 * TODO: Is there some way to trigger this for every attempt to
1416 * use the network? */
1417 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1420 if (!store_account) {
1421 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1422 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1423 "cannot get tny store account for %s\n", account_name);
1428 /* Get the transport account, we can not do it in the thread
1429 due to some problems with dbus */
1430 transport_account = (TnyTransportAccount *)
1431 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1433 if (!transport_account) {
1434 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1435 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1436 "cannot get tny transport account for %s\n", account_name);
1440 /* Create the helper object */
1441 info = g_slice_new (UpdateAccountInfo);
1442 info->mail_op = self;
1443 info->account = store_account;
1444 info->transport_account = transport_account;
1445 info->callback = callback;
1446 info->user_data = user_data;
1448 /* Get the message size limit */
1449 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1450 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1451 if (info->max_size == 0)
1452 info->max_size = G_MAXINT;
1454 info->max_size = info->max_size * KB;
1456 /* Get per-account retrieval type */
1457 mgr = modest_runtime_get_account_mgr ();
1458 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1459 MODEST_ACCOUNT_RETRIEVE, FALSE);
1461 /* Get per-account message amount retrieval limit */
1462 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1463 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1464 if (info->retrieve_limit == 0)
1465 info->retrieve_limit = G_MAXINT;
1467 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1469 /* Set account busy */
1470 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1471 priv->account_name = g_strdup(account_name);
1473 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1478 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1480 callback (self, 0, user_data);
1481 modest_mail_operation_notify_end (self);
1485 /* ******************************************************************* */
1486 /* ************************** STORE ACTIONS ************************* */
1487 /* ******************************************************************* */
1491 modest_mail_operation_create_folder (ModestMailOperation *self,
1492 TnyFolderStore *parent,
1495 ModestMailOperationPrivate *priv;
1496 TnyFolder *new_folder = NULL;
1498 TnyList *list = tny_simple_list_new ();
1499 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1501 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1502 g_return_val_if_fail (name, NULL);
1504 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1506 /* Check for already existing folder */
1507 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1508 tny_folder_store_get_folders (parent, list, query, NULL);
1509 g_object_unref (G_OBJECT (query));
1511 if (tny_list_get_length (list) > 0) {
1512 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1514 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1515 _CS("ckdg_ib_folder_already_exists"));
1518 g_object_unref (G_OBJECT (list));
1521 if (TNY_IS_FOLDER (parent)) {
1522 /* Check folder rules */
1523 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1524 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1525 /* Set status failed and set an error */
1526 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1527 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1528 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1529 _("mail_in_ui_folder_create_error"));
1533 if (!strcmp (name, " ") || strchr (name, '/')) {
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_create_error"));
1541 /* Create the folder */
1542 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1543 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1545 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1548 /* Notify about operation end */
1549 modest_mail_operation_notify_end (self);
1555 modest_mail_operation_remove_folder (ModestMailOperation *self,
1557 gboolean remove_to_trash)
1559 TnyAccount *account;
1560 ModestMailOperationPrivate *priv;
1561 ModestTnyFolderRules rules;
1563 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1564 g_return_if_fail (TNY_IS_FOLDER (folder));
1566 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1568 /* Check folder rules */
1569 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1570 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1571 /* Set status failed and set an error */
1572 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1573 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1574 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1575 _("mail_in_ui_folder_delete_error"));
1579 /* Get the account */
1580 account = modest_tny_folder_get_account (folder);
1581 priv->account = g_object_ref(account);
1583 /* Delete folder or move to trash */
1584 if (remove_to_trash) {
1585 TnyFolder *trash_folder = NULL;
1586 trash_folder = modest_tny_account_get_special_folder (account,
1587 TNY_FOLDER_TYPE_TRASH);
1588 /* TODO: error_handling */
1590 modest_mail_operation_xfer_folder (self, folder,
1591 TNY_FOLDER_STORE (trash_folder),
1593 g_object_unref (trash_folder);
1596 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1598 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1599 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1602 g_object_unref (G_OBJECT (parent));
1604 g_object_unref (G_OBJECT (account));
1607 /* Notify about operation end */
1608 modest_mail_operation_notify_end (self);
1612 transfer_folder_status_cb (GObject *obj,
1616 ModestMailOperation *self;
1617 ModestMailOperationPrivate *priv;
1618 ModestMailOperationState *state;
1619 XFerMsgAsyncHelper *helper;
1621 g_return_if_fail (status != NULL);
1622 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1624 helper = (XFerMsgAsyncHelper *) user_data;
1625 g_return_if_fail (helper != NULL);
1627 self = helper->mail_op;
1628 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1630 priv->done = status->position;
1631 priv->total = status->of_total;
1633 state = modest_mail_operation_clone_state (self);
1634 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1635 gdk_threads_enter ();
1637 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1638 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1639 gdk_threads_leave ();
1641 g_slice_free (ModestMailOperationState, state);
1646 transfer_folder_cb (TnyFolder *folder,
1647 TnyFolderStore *into,
1649 TnyFolder *new_folder,
1653 XFerMsgAsyncHelper *helper;
1654 ModestMailOperation *self = NULL;
1655 ModestMailOperationPrivate *priv = NULL;
1657 helper = (XFerMsgAsyncHelper *) user_data;
1658 g_return_if_fail (helper != NULL);
1660 self = helper->mail_op;
1661 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1664 priv->error = g_error_copy (*err);
1666 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1667 } else if (cancelled) {
1668 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1669 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1670 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1671 _("Transference of %s was cancelled."),
1672 tny_folder_get_name (folder));
1675 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1678 /* Notify about operation end */
1679 modest_mail_operation_notify_end (self);
1681 /* If user defined callback function was defined, call it */
1682 if (helper->user_callback) {
1683 gdk_threads_enter ();
1684 helper->user_callback (priv->source, helper->user_data);
1685 gdk_threads_leave ();
1689 g_object_unref (helper->mail_op);
1690 g_slice_free (XFerMsgAsyncHelper, helper);
1695 * This function checks if the new name is a valid name for our local
1696 * folders account. The new name could not be the same than then name
1697 * of any of the mandatory local folders
1699 * We can not rely on tinymail because tinymail does not check the
1700 * name of the virtual folders that the account could have in the case
1701 * that we're doing a rename (because it directly calls Camel which
1702 * knows nothing about our virtual folders).
1704 * In the case of an actual copy/move (i.e. move/copy a folder between
1705 * accounts) tinymail uses the tny_folder_store_create_account which
1706 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1707 * checks the new name of the folder, so this call in that case
1708 * wouldn't be needed. *But* NOTE that if tinymail changes its
1709 * implementation (if folder transfers within the same account is no
1710 * longer implemented as a rename) this call will allow Modest to work
1713 * If the new name is not valid, this function will set the status to
1714 * failed and will set also an error in the mail operation
1717 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1718 TnyFolderStore *into,
1719 const gchar *new_name)
1721 if (TNY_IS_ACCOUNT (into) &&
1722 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1723 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1725 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1726 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1727 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1728 _("FIXME: folder name already in use"));
1735 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1737 TnyFolderStore *parent,
1738 gboolean delete_original,
1739 XferMsgsAsynUserCallback user_callback,
1742 ModestMailOperationPrivate *priv = NULL;
1743 ModestTnyFolderRules parent_rules = 0, rules;
1744 XFerMsgAsyncHelper *helper = NULL;
1746 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1747 g_return_if_fail (TNY_IS_FOLDER (folder));
1749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1751 /* Get account and set it into mail_operation */
1752 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1753 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1755 /* Get folder rules */
1756 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1757 if (TNY_IS_FOLDER (parent))
1758 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1760 /* The moveable restriction is applied also to copy operation */
1761 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1762 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1763 /* Set status failed and set an error */
1764 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1765 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1766 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1767 _("mail_in_ui_folder_move_target_error"));
1769 /* Notify the queue */
1770 modest_mail_operation_notify_end (self);
1771 } else if (TNY_IS_FOLDER (parent) &&
1772 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1773 /* Set status failed and set an error */
1774 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1775 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1776 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1777 _("FIXME: parent folder does not accept new folders"));
1779 /* Notify the queue */
1780 modest_mail_operation_notify_end (self);
1784 /* Check that the new folder name is not used by any
1785 special local folder */
1786 if (new_name_valid_if_local_account (priv, parent,
1787 tny_folder_get_name (folder))) {
1788 /* Create the helper */
1789 helper = g_slice_new0 (XFerMsgAsyncHelper);
1790 helper->mail_op = g_object_ref(self);
1791 helper->dest_folder = NULL;
1792 helper->headers = NULL;
1793 helper->user_callback = user_callback;
1794 helper->user_data = user_data;
1796 /* Move/Copy folder */
1797 tny_folder_copy_async (folder,
1799 tny_folder_get_name (folder),
1802 transfer_folder_status_cb,
1805 modest_mail_operation_notify_end (self);
1811 modest_mail_operation_rename_folder (ModestMailOperation *self,
1815 ModestMailOperationPrivate *priv;
1816 ModestTnyFolderRules rules;
1817 XFerMsgAsyncHelper *helper;
1819 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1820 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1821 g_return_if_fail (name);
1823 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1825 /* Get account and set it into mail_operation */
1826 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1828 /* Check folder rules */
1829 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1830 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
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_FOLDER_RULES,
1835 _("FIXME: unable to rename"));
1837 /* Notify about operation end */
1838 modest_mail_operation_notify_end (self);
1839 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1840 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1841 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1842 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1843 _("FIXME: unable to rename"));
1844 /* Notify about operation end */
1845 modest_mail_operation_notify_end (self);
1847 TnyFolderStore *into;
1849 into = tny_folder_get_folder_store (folder);
1851 /* Check that the new folder name is not used by any
1852 special local folder */
1853 if (new_name_valid_if_local_account (priv, into, name)) {
1854 /* Create the helper */
1855 helper = g_slice_new0 (XFerMsgAsyncHelper);
1856 helper->mail_op = g_object_ref(self);
1857 helper->dest_folder = NULL;
1858 helper->headers = NULL;
1859 helper->user_callback = NULL;
1860 helper->user_data = NULL;
1862 /* Rename. Camel handles folder subscription/unsubscription */
1863 tny_folder_copy_async (folder, into, name, TRUE,
1865 transfer_folder_status_cb,
1868 modest_mail_operation_notify_end (self);
1870 g_object_unref (into);
1874 /* ******************************************************************* */
1875 /* ************************** MSG ACTIONS ************************* */
1876 /* ******************************************************************* */
1878 void modest_mail_operation_get_msg (ModestMailOperation *self,
1880 GetMsgAsyncUserCallback user_callback,
1883 GetMsgAsyncHelper *helper = NULL;
1885 ModestMailOperationPrivate *priv;
1887 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1888 g_return_if_fail (TNY_IS_HEADER (header));
1890 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1891 folder = tny_header_get_folder (header);
1893 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1895 /* Get message from folder */
1897 /* Get account and set it into mail_operation */
1898 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1900 helper = g_slice_new0 (GetMsgAsyncHelper);
1901 helper->mail_op = self;
1902 helper->user_callback = user_callback;
1903 helper->user_data = user_data;
1904 helper->header = g_object_ref (header);
1906 // The callback's reference so that the mail op is not
1907 // finalized until the async operation is completed even if
1908 // the user canceled the request meanwhile.
1909 g_object_ref (G_OBJECT (helper->mail_op));
1911 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1913 g_object_unref (G_OBJECT (folder));
1915 /* Set status failed and set an error */
1916 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1917 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1918 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1919 _("Error trying to get a message. No folder found for header"));
1921 /* Notify the queue */
1922 modest_mail_operation_notify_end (self);
1927 idle_get_mime_part_size_cb (gpointer userdata)
1929 GetMimePartSizeInfo *idle_info;
1931 idle_info = (GetMimePartSizeInfo *) userdata;
1933 gdk_threads_enter ();
1934 idle_info->callback (idle_info->mail_op,
1936 idle_info->userdata);
1937 gdk_threads_leave ();
1939 g_object_unref (idle_info->mail_op);
1940 g_slice_free (GetMimePartSizeInfo, idle_info);
1946 get_mime_part_size_thread (gpointer thr_user_data)
1948 GetMimePartSizeInfo *info;
1949 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1953 ModestMailOperationPrivate *priv;
1955 info = (GetMimePartSizeInfo *) thr_user_data;
1956 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1958 stream = tny_camel_mem_stream_new ();
1959 tny_mime_part_decode_to_stream (info->mime_part, stream);
1960 tny_stream_reset (stream);
1961 if (tny_stream_is_eos (stream)) {
1962 tny_stream_close (stream);
1963 stream = tny_mime_part_get_stream (info->mime_part);
1966 while (!tny_stream_is_eos (stream)) {
1967 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1968 total += readed_size;
1971 if (info->callback) {
1972 GetMimePartSizeInfo *idle_info;
1974 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1975 idle_info->mail_op = g_object_ref (info->mail_op);
1976 idle_info->size = total;
1977 idle_info->callback = info->callback;
1978 idle_info->userdata = info->userdata;
1979 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1982 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1984 g_object_unref (info->mail_op);
1985 g_object_unref (stream);
1986 g_object_unref (info->mime_part);
1987 g_slice_free (GetMimePartSizeInfo, info);
1993 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1995 GetMimePartSizeCallback user_callback,
1997 GDestroyNotify notify)
1999 GetMimePartSizeInfo *info;
2000 ModestMailOperationPrivate *priv;
2003 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2004 g_return_if_fail (TNY_IS_MIME_PART (part));
2006 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2008 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2009 info = g_slice_new0 (GetMimePartSizeInfo);
2010 info->mail_op = g_object_ref (self);
2011 info->mime_part = g_object_ref (part);
2012 info->callback = user_callback;
2013 info->userdata = user_data;
2015 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2020 get_msg_cb (TnyFolder *folder,
2026 GetMsgAsyncHelper *helper = NULL;
2027 ModestMailOperation *self = NULL;
2028 ModestMailOperationPrivate *priv = NULL;
2030 helper = (GetMsgAsyncHelper *) user_data;
2031 g_return_if_fail (helper != NULL);
2032 self = helper->mail_op;
2033 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2034 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2036 /* Check errors and cancel */
2038 priv->error = g_error_copy (*error);
2039 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2040 } else if (cancelled) {
2041 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2042 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2043 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2044 _("Error trying to refresh the contents of %s"),
2045 tny_folder_get_name (folder));
2047 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2050 /* If user defined callback function was defined, call it even
2051 if the operation failed*/
2052 if (helper->user_callback) {
2053 /* This callback is called into an iddle by tinymail,
2054 and idles are not in the main lock */
2055 gdk_threads_enter ();
2056 helper->user_callback (self, helper->header, msg, helper->user_data);
2057 gdk_threads_leave ();
2060 /* Notify about operation end */
2061 modest_mail_operation_notify_end (self);
2063 g_object_unref (helper->mail_op);
2064 g_object_unref (helper->header);
2065 g_slice_free (GetMsgAsyncHelper, helper);
2070 get_msg_status_cb (GObject *obj,
2074 GetMsgAsyncHelper *helper = NULL;
2075 ModestMailOperation *self;
2076 ModestMailOperationPrivate *priv;
2077 ModestMailOperationState *state;
2079 g_return_if_fail (status != NULL);
2080 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2082 helper = (GetMsgAsyncHelper *) user_data;
2083 g_return_if_fail (helper != NULL);
2085 self = helper->mail_op;
2086 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2091 state = modest_mail_operation_clone_state (self);
2092 state->bytes_done = status->position;
2093 state->bytes_total = status->of_total;
2094 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2095 gdk_threads_enter ();
2097 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2098 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2099 gdk_threads_leave ();
2101 g_slice_free (ModestMailOperationState, state);
2104 /****************************************************/
2106 ModestMailOperation *mail_op;
2108 GetMsgAsyncUserCallback user_callback;
2110 GDestroyNotify notify;
2114 GetMsgAsyncUserCallback user_callback;
2118 ModestMailOperation *mail_op;
2119 } NotifyGetMsgsInfo;
2123 * Used by get_msgs_full_thread to call the user_callback for each
2124 * message that has been read
2127 notify_get_msgs_full (gpointer data)
2129 NotifyGetMsgsInfo *info;
2131 info = (NotifyGetMsgsInfo *) data;
2133 /* Call the user callback. Idles are not in the main lock, so
2135 gdk_threads_enter ();
2136 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2137 gdk_threads_leave ();
2139 g_slice_free (NotifyGetMsgsInfo, info);
2145 * Used by get_msgs_full_thread to free al the thread resources and to
2146 * call the destroy function for the passed user_data
2149 get_msgs_full_destroyer (gpointer data)
2151 GetFullMsgsInfo *info;
2153 info = (GetFullMsgsInfo *) data;
2156 gdk_threads_enter ();
2157 info->notify (info->user_data);
2158 gdk_threads_leave ();
2162 g_object_unref (info->headers);
2163 g_slice_free (GetFullMsgsInfo, info);
2169 get_msgs_full_thread (gpointer thr_user_data)
2171 GetFullMsgsInfo *info;
2172 ModestMailOperationPrivate *priv = NULL;
2173 TnyIterator *iter = NULL;
2175 info = (GetFullMsgsInfo *) thr_user_data;
2176 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2178 iter = tny_list_create_iterator (info->headers);
2179 while (!tny_iterator_is_done (iter)) {
2183 header = TNY_HEADER (tny_iterator_get_current (iter));
2184 folder = tny_header_get_folder (header);
2186 /* Get message from folder */
2189 /* The callback will call it per each header */
2190 msg = tny_folder_get_msg (folder, header, &(priv->error));
2193 ModestMailOperationState *state;
2198 /* notify progress */
2199 state = modest_mail_operation_clone_state (info->mail_op);
2200 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2201 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2202 pair, (GDestroyNotify) modest_pair_free);
2204 /* The callback is the responsible for
2205 freeing the message */
2206 if (info->user_callback) {
2207 NotifyGetMsgsInfo *info_notify;
2208 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2209 info_notify->user_callback = info->user_callback;
2210 info_notify->mail_op = info->mail_op;
2211 info_notify->header = g_object_ref (header);
2212 info_notify->msg = g_object_ref (msg);
2213 info_notify->user_data = info->user_data;
2214 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2215 notify_get_msgs_full,
2218 g_object_unref (msg);
2221 /* Set status failed and set an error */
2222 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2223 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2224 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2225 "Error trying to get a message. No folder found for header");
2227 g_object_unref (header);
2228 tny_iterator_next (iter);
2231 /* Set operation status */
2232 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2233 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2235 /* Notify about operation end */
2236 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2238 /* Free thread resources. Will be called after all previous idles */
2239 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2245 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2246 TnyList *header_list,
2247 GetMsgAsyncUserCallback user_callback,
2249 GDestroyNotify notify)
2251 TnyHeader *header = NULL;
2252 TnyFolder *folder = NULL;
2254 ModestMailOperationPrivate *priv = NULL;
2255 GetFullMsgsInfo *info = NULL;
2256 gboolean size_ok = TRUE;
2258 TnyIterator *iter = NULL;
2260 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2262 /* Init mail operation */
2263 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2264 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2266 priv->total = tny_list_get_length(header_list);
2268 /* Get account and set it into mail_operation */
2269 if (tny_list_get_length (header_list) >= 1) {
2270 iter = tny_list_create_iterator (header_list);
2271 header = TNY_HEADER (tny_iterator_get_current (iter));
2272 folder = tny_header_get_folder (header);
2273 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2274 g_object_unref (header);
2275 g_object_unref (folder);
2277 if (tny_list_get_length (header_list) == 1) {
2278 g_object_unref (iter);
2283 /* Get msg size limit */
2284 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2285 MODEST_CONF_MSG_SIZE_LIMIT,
2288 g_clear_error (&(priv->error));
2289 max_size = G_MAXINT;
2291 max_size = max_size * KB;
2294 /* Check message size limits. If there is only one message
2295 always retrieve it */
2297 while (!tny_iterator_is_done (iter) && size_ok) {
2298 header = TNY_HEADER (tny_iterator_get_current (iter));
2299 if (tny_header_get_message_size (header) >= max_size)
2301 g_object_unref (header);
2302 tny_iterator_next (iter);
2304 g_object_unref (iter);
2308 /* Create the info */
2309 info = g_slice_new0 (GetFullMsgsInfo);
2310 info->mail_op = self;
2311 info->user_callback = user_callback;
2312 info->user_data = user_data;
2313 info->headers = g_object_ref (header_list);
2314 info->notify = notify;
2316 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2318 /* Set status failed and set an error */
2319 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2320 /* FIXME: the error msg is different for pop */
2321 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2322 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2323 _("emev_ni_ui_imap_msg_size_exceed_error"));
2324 /* Remove from queue and free resources */
2325 modest_mail_operation_notify_end (self);
2333 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2334 gboolean remove_to_trash /*ignored*/)
2337 ModestMailOperationPrivate *priv;
2339 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2340 g_return_if_fail (TNY_IS_HEADER (header));
2342 if (remove_to_trash)
2343 g_warning ("remove to trash is not implemented");
2345 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2346 folder = tny_header_get_folder (header);
2348 /* Get account and set it into mail_operation */
2349 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2351 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2354 tny_folder_remove_msg (folder, header, &(priv->error));
2356 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2357 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2359 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2360 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2361 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2362 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2365 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2371 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2373 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2376 g_object_unref (G_OBJECT (folder));
2378 /* Notify about operation end */
2379 modest_mail_operation_notify_end (self);
2383 transfer_msgs_status_cb (GObject *obj,
2387 XFerMsgAsyncHelper *helper = NULL;
2388 ModestMailOperation *self;
2389 ModestMailOperationPrivate *priv;
2390 ModestMailOperationState *state;
2393 g_return_if_fail (status != NULL);
2394 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2396 helper = (XFerMsgAsyncHelper *) user_data;
2397 g_return_if_fail (helper != NULL);
2399 self = helper->mail_op;
2400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2402 priv->done = status->position;
2403 priv->total = status->of_total;
2405 state = modest_mail_operation_clone_state (self);
2406 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2407 gdk_threads_enter ();
2409 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2410 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2411 gdk_threads_leave ();
2413 g_slice_free (ModestMailOperationState, state);
2418 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2420 XFerMsgAsyncHelper *helper;
2421 ModestMailOperation *self;
2422 ModestMailOperationPrivate *priv;
2424 helper = (XFerMsgAsyncHelper *) user_data;
2425 self = helper->mail_op;
2427 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2430 priv->error = g_error_copy (*err);
2432 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2433 } else if (cancelled) {
2434 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2435 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2436 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2437 _("Error trying to refresh the contents of %s"),
2438 tny_folder_get_name (folder));
2441 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2444 /* Notify about operation end */
2445 modest_mail_operation_notify_end (self);
2447 /* If user defined callback function was defined, call it */
2448 if (helper->user_callback) {
2449 gdk_threads_enter ();
2450 helper->user_callback (priv->source, helper->user_data);
2451 gdk_threads_leave ();
2455 g_object_unref (helper->headers);
2456 g_object_unref (helper->dest_folder);
2457 g_object_unref (helper->mail_op);
2458 g_slice_free (XFerMsgAsyncHelper, helper);
2459 g_object_unref (folder);
2464 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2467 gboolean delete_original,
2468 XferMsgsAsynUserCallback user_callback,
2471 ModestMailOperationPrivate *priv;
2473 TnyFolder *src_folder;
2474 XFerMsgAsyncHelper *helper;
2476 ModestTnyFolderRules rules;
2477 const gchar *id1 = NULL;
2478 const gchar *id2 = NULL;
2479 gboolean same_folder = FALSE;
2481 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2482 g_return_if_fail (TNY_IS_LIST (headers));
2483 g_return_if_fail (TNY_IS_FOLDER (folder));
2485 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2488 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2490 /* Apply folder rules */
2491 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2492 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2493 /* Set status failed and set an error */
2494 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2495 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2496 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2497 _CS("ckct_ib_unable_to_paste_here"));
2498 /* Notify the queue */
2499 modest_mail_operation_notify_end (self);
2503 /* Get source folder */
2504 iter = tny_list_create_iterator (headers);
2505 header = TNY_HEADER (tny_iterator_get_current (iter));
2506 src_folder = tny_header_get_folder (header);
2507 g_object_unref (header);
2508 g_object_unref (iter);
2510 /* Check folder source and destination */
2511 id1 = tny_folder_get_id (src_folder);
2512 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2513 same_folder = !g_ascii_strcasecmp (id1, id2);
2515 /* Set status failed and set an error */
2516 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2517 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2518 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2519 _("mcen_ib_unable_to_copy_samefolder"));
2521 /* Notify the queue */
2522 modest_mail_operation_notify_end (self);
2525 g_object_unref (src_folder);
2529 /* Create the helper */
2530 helper = g_slice_new0 (XFerMsgAsyncHelper);
2531 helper->mail_op = g_object_ref(self);
2532 helper->dest_folder = g_object_ref(folder);
2533 helper->headers = g_object_ref(headers);
2534 helper->user_callback = user_callback;
2535 helper->user_data = user_data;
2537 /* Get account and set it into mail_operation */
2538 priv->account = modest_tny_folder_get_account (src_folder);
2540 /* Transfer messages */
2541 tny_folder_transfer_msgs_async (src_folder,
2546 transfer_msgs_status_cb,
2552 on_refresh_folder (TnyFolder *folder,
2557 RefreshAsyncHelper *helper = NULL;
2558 ModestMailOperation *self = NULL;
2559 ModestMailOperationPrivate *priv = NULL;
2561 helper = (RefreshAsyncHelper *) user_data;
2562 self = helper->mail_op;
2563 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2566 priv->error = g_error_copy (*error);
2567 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2572 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2573 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2574 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2575 _("Error trying to refresh the contents of %s"),
2576 tny_folder_get_name (folder));
2580 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2582 /* Call user defined callback, if it exists */
2583 if (helper->user_callback) {
2584 gdk_threads_enter ();
2585 helper->user_callback (self, folder, helper->user_data);
2586 gdk_threads_leave ();
2590 /* g_object_unref (helper->mail_op); */
2591 g_slice_free (RefreshAsyncHelper, helper);
2593 /* Notify about operation end */
2594 modest_mail_operation_notify_end (self);
2598 on_refresh_folder_status_update (GObject *obj,
2602 RefreshAsyncHelper *helper = NULL;
2603 ModestMailOperation *self = NULL;
2604 ModestMailOperationPrivate *priv = NULL;
2605 ModestMailOperationState *state;
2607 g_return_if_fail (user_data != NULL);
2608 g_return_if_fail (status != NULL);
2609 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2611 helper = (RefreshAsyncHelper *) user_data;
2612 self = helper->mail_op;
2613 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2615 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2617 priv->done = status->position;
2618 priv->total = status->of_total;
2620 state = modest_mail_operation_clone_state (self);
2621 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2622 gdk_threads_enter ();
2624 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2625 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2626 gdk_threads_leave ();
2628 g_slice_free (ModestMailOperationState, state);
2632 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2634 RefreshAsyncUserCallback user_callback,
2637 ModestMailOperationPrivate *priv = NULL;
2638 RefreshAsyncHelper *helper = NULL;
2640 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2642 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2644 /* Get account and set it into mail_operation */
2645 priv->account = modest_tny_folder_get_account (folder);
2647 /* Create the helper */
2648 helper = g_slice_new0 (RefreshAsyncHelper);
2649 helper->mail_op = g_object_ref (self);
2650 helper->user_callback = user_callback;
2651 helper->user_data = user_data;
2653 /* Refresh the folder. TODO: tinymail could issue a status
2654 updates before the callback call then this could happen. We
2655 must review the design */
2656 tny_folder_refresh_async (folder,
2658 on_refresh_folder_status_update,
2664 * It's used by the mail operation queue to notify the observers
2665 * attached to that signal that the operation finished. We need to use
2666 * that because tinymail does not give us the progress of a given
2667 * operation when it finishes (it directly calls the operation
2671 modest_mail_operation_notify_end (ModestMailOperation *self)
2673 ModestMailOperationState *state;
2674 ModestMailOperationPrivate *priv = NULL;
2676 g_return_if_fail (self);
2678 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2680 /* Set the account back to not busy */
2681 if (priv->account_name) {
2682 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2683 priv->account_name, FALSE);
2684 g_free(priv->account_name);
2685 priv->account_name = NULL;
2688 /* Notify the observers about the mail operation end */
2689 /* We do not wrapp this emission because we assume that this
2690 function is always called from within the main lock */
2691 state = modest_mail_operation_clone_state (self);
2692 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2693 g_slice_free (ModestMailOperationState, state);