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));
1008 tny_iterator_next (iter);
1010 g_object_unref (G_OBJECT (iter));
1011 g_object_unref (G_OBJECT (folders));
1015 * Issues the "progress-changed" signal. The timer won't be removed,
1016 * so you must call g_source_remove to stop the signal emission
1019 idle_notify_progress (gpointer data)
1021 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1022 ModestMailOperationState *state;
1024 state = modest_mail_operation_clone_state (mail_op);
1025 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1026 gdk_threads_enter ();
1028 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1029 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1030 gdk_threads_leave ();
1032 g_slice_free (ModestMailOperationState, state);
1038 * Issues the "progress-changed" signal and removes the timer. It uses
1039 * a lock to ensure that the progress information of the mail
1040 * operation is not modified while there are notifications pending
1043 idle_notify_progress_once (gpointer data)
1047 pair = (ModestPair *) data;
1049 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1050 gdk_threads_enter ();
1052 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1053 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1054 gdk_threads_leave ();
1057 /* Free the state and the reference to the mail operation */
1058 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1059 g_object_unref (pair->first);
1065 * Used to notify the queue from the main
1066 * loop. We call it inside an idle call to achieve that
1069 idle_notify_queue (gpointer data)
1071 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1073 /* Do not need to block, the notify end will do it for us */
1074 modest_mail_operation_notify_end (mail_op);
1075 g_object_unref (mail_op);
1081 compare_headers_by_date (gconstpointer a,
1084 TnyHeader **header1, **header2;
1085 time_t sent1, sent2;
1087 header1 = (TnyHeader **) a;
1088 header2 = (TnyHeader **) b;
1090 sent1 = tny_header_get_date_sent (*header1);
1091 sent2 = tny_header_get_date_sent (*header2);
1093 /* We want the most recent ones (greater time_t) at the
1102 set_last_updated_idle (gpointer data)
1104 gdk_threads_enter ();
1106 /* It does not matter if the time is not exactly the same than
1107 the time when this idle was called, it's just an
1108 approximation and it won't be very different */
1109 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1111 MODEST_ACCOUNT_LAST_UPDATED,
1115 gdk_threads_leave ();
1121 idle_update_account_cb (gpointer data)
1123 UpdateAccountInfo *idle_info;
1125 idle_info = (UpdateAccountInfo *) data;
1127 gdk_threads_enter ();
1128 idle_info->callback (idle_info->mail_op,
1129 idle_info->new_headers,
1130 idle_info->user_data);
1131 gdk_threads_leave ();
1134 g_object_unref (idle_info->mail_op);
1142 update_account_thread (gpointer thr_user_data)
1144 static gboolean first_time = TRUE;
1145 UpdateAccountInfo *info = NULL;
1146 TnyList *all_folders = NULL;
1147 GPtrArray *new_headers = NULL;
1148 TnyIterator *iter = NULL;
1149 TnyFolderStoreQuery *query = NULL;
1150 ModestMailOperationPrivate *priv = NULL;
1151 ModestTnySendQueue *send_queue = NULL;
1152 gint num_new_headers = 0;
1154 info = (UpdateAccountInfo *) thr_user_data;
1155 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1157 /* Get account and set it into mail_operation */
1158 priv->account = g_object_ref (info->account);
1161 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1162 * show any updates unless we do that
1164 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT (priv->account))
1165 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1167 /* Get all the folders. We can do it synchronously because
1168 we're already running in a different thread than the UI */
1169 all_folders = tny_simple_list_new ();
1170 query = tny_folder_store_query_new ();
1171 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1172 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1177 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1181 iter = tny_list_create_iterator (all_folders);
1182 while (!tny_iterator_is_done (iter)) {
1183 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1185 recurse_folders (folder, query, all_folders);
1186 g_object_unref (folder);
1188 tny_iterator_next (iter);
1190 g_object_unref (G_OBJECT (iter));
1192 /* Update status and notify. We need to call the notification
1193 with a source function in order to call it from the main
1194 loop. We need that in order not to get into trouble with
1195 Gtk+. We use a timeout in order to provide more status
1196 information, because the sync tinymail call does not
1197 provide it for the moment */
1198 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1200 /* Refresh folders */
1201 num_new_headers = 0;
1202 new_headers = g_ptr_array_new ();
1203 iter = tny_list_create_iterator (all_folders);
1205 while (!tny_iterator_is_done (iter) && !priv->error &&
1206 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1208 InternalFolderObserver *observer;
1209 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1211 /* Refresh the folder */
1212 /* Our observer receives notification of new emails during folder refreshes,
1213 * so we can use observer->new_headers.
1215 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1216 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1218 /* This gets the status information (headers) from the server.
1219 * We use the blocking version, because we are already in a separate
1223 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1224 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1227 /* If the retrieve type is full messages, refresh and get the messages */
1228 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1230 iter = tny_list_create_iterator (observer->new_headers);
1231 while (!tny_iterator_is_done (iter)) {
1232 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1234 /* Apply per-message size limits */
1235 if (tny_header_get_message_size (header) < info->max_size)
1236 g_ptr_array_add (new_headers, g_object_ref (header));
1238 g_object_unref (header);
1239 tny_iterator_next (iter);
1241 g_object_unref (iter);
1243 /* We do not need to do it the first time
1244 because it's automatically done by the tree
1246 if (G_UNLIKELY (!first_time))
1247 tny_folder_poke_status (TNY_FOLDER (folder));
1249 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1250 g_object_unref (observer);
1254 g_object_unref (G_OBJECT (folder));
1257 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1259 tny_iterator_next (iter);
1262 g_object_unref (G_OBJECT (iter));
1263 g_source_remove (timeout);
1265 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1266 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1267 new_headers->len > 0) {
1271 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1273 /* Apply message count limit */
1274 /* If the number of messages exceeds the maximum, ask the
1275 * user to download them all,
1276 * as per the UI spec "Retrieval Limits" section in 4.4:
1278 if (new_headers->len > info->retrieve_limit) {
1279 /* TODO: Ask the user, instead of just
1281 * mail_nc_msg_count_limit_exceeded, with 'Get
1282 * all' and 'Newest only' buttons. */
1283 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1284 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1285 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1286 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1287 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1292 priv->total = MIN (new_headers->len, info->retrieve_limit);
1293 while (msg_num < priv->total) {
1295 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1296 TnyFolder *folder = tny_header_get_folder (header);
1297 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1298 ModestMailOperationState *state;
1302 /* We can not just use the mail operation because the
1303 values of done and total could change before the
1305 state = modest_mail_operation_clone_state (info->mail_op);
1306 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1307 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1308 pair, (GDestroyNotify) modest_pair_free);
1310 g_object_unref (msg);
1311 g_object_unref (folder);
1317 /* Get the number of new headers and free them */
1318 num_new_headers = new_headers->len;
1319 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1320 g_ptr_array_free (new_headers, FALSE);
1322 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1325 /* Perform send (if operation was not cancelled) */
1326 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1329 if (priv->account != NULL)
1330 g_object_unref (priv->account);
1331 priv->account = g_object_ref (info->transport_account);
1333 send_queue = modest_runtime_get_send_queue (info->transport_account);
1335 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1336 modest_tny_send_queue_try_to_send (send_queue);
1337 /* g_source_remove (timeout); */
1339 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1340 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1341 "cannot create a send queue for %s\n",
1342 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1346 /* Check if the operation was a success */
1348 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1350 /* Update the last updated key */
1351 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1352 set_last_updated_idle,
1353 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1354 (GDestroyNotify) g_free);
1359 if (info->callback) {
1360 UpdateAccountInfo *idle_info;
1362 /* This thread is not in the main lock */
1363 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1364 idle_info->mail_op = g_object_ref (info->mail_op);
1365 idle_info->new_headers = num_new_headers;
1366 idle_info->callback = info->callback;
1367 g_idle_add (idle_update_account_cb, idle_info);
1370 /* Notify about operation end. Note that the info could be
1371 freed before this idle happens, but the mail operation will
1373 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1376 g_object_unref (query);
1377 g_object_unref (all_folders);
1378 g_object_unref (info->account);
1379 g_object_unref (info->transport_account);
1380 g_free (info->retrieve_type);
1381 g_slice_free (UpdateAccountInfo, info);
1389 modest_mail_operation_update_account (ModestMailOperation *self,
1390 const gchar *account_name,
1391 UpdateAccountCallback callback,
1394 GThread *thread = NULL;
1395 UpdateAccountInfo *info = NULL;
1396 ModestMailOperationPrivate *priv = NULL;
1397 ModestAccountMgr *mgr = NULL;
1398 TnyStoreAccount *store_account = NULL;
1399 TnyTransportAccount *transport_account = NULL;
1401 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1402 g_return_val_if_fail (account_name, FALSE);
1404 /* Init mail operation. Set total and done to 0, and do not
1405 update them, this way the progress objects will know that
1406 we have no clue about the number of the objects */
1407 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1410 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1412 /* Get the Modest account */
1413 store_account = (TnyStoreAccount *)
1414 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1416 TNY_ACCOUNT_TYPE_STORE);
1418 /* Make sure that we have a connection, and request one
1420 * TODO: Is there some way to trigger this for every attempt to
1421 * use the network? */
1422 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1425 if (!store_account) {
1426 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1427 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1428 "cannot get tny store account for %s\n", account_name);
1433 /* Get the transport account, we can not do it in the thread
1434 due to some problems with dbus */
1435 transport_account = (TnyTransportAccount *)
1436 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1438 if (!transport_account) {
1439 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1440 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1441 "cannot get tny transport account for %s\n", account_name);
1445 /* Create the helper object */
1446 info = g_slice_new (UpdateAccountInfo);
1447 info->mail_op = self;
1448 info->account = store_account;
1449 info->transport_account = transport_account;
1450 info->callback = callback;
1451 info->user_data = user_data;
1453 /* Get the message size limit */
1454 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1455 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1456 if (info->max_size == 0)
1457 info->max_size = G_MAXINT;
1459 info->max_size = info->max_size * KB;
1461 /* Get per-account retrieval type */
1462 mgr = modest_runtime_get_account_mgr ();
1463 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1464 MODEST_ACCOUNT_RETRIEVE, FALSE);
1466 /* Get per-account message amount retrieval limit */
1467 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1468 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1469 if (info->retrieve_limit == 0)
1470 info->retrieve_limit = G_MAXINT;
1472 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1474 /* Set account busy */
1475 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1476 priv->account_name = g_strdup(account_name);
1478 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1483 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1485 callback (self, 0, user_data);
1486 modest_mail_operation_notify_end (self);
1490 /* ******************************************************************* */
1491 /* ************************** STORE ACTIONS ************************* */
1492 /* ******************************************************************* */
1496 modest_mail_operation_create_folder (ModestMailOperation *self,
1497 TnyFolderStore *parent,
1500 ModestMailOperationPrivate *priv;
1501 TnyFolder *new_folder = NULL;
1503 TnyList *list = tny_simple_list_new ();
1504 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1506 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1507 g_return_val_if_fail (name, NULL);
1509 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1511 /* Check for already existing folder */
1512 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1513 tny_folder_store_get_folders (parent, list, query, NULL);
1514 g_object_unref (G_OBJECT (query));
1516 if (tny_list_get_length (list) > 0) {
1517 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1518 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1519 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1520 _CS("ckdg_ib_folder_already_exists"));
1523 g_object_unref (G_OBJECT (list));
1526 if (TNY_IS_FOLDER (parent)) {
1527 /* Check folder rules */
1528 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1529 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1530 /* Set status failed and set an error */
1531 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1532 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1533 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1534 _("mail_in_ui_folder_create_error"));
1538 if (!strcmp (name, " ") || strchr (name, '/')) {
1539 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1540 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1541 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1542 _("mail_in_ui_folder_create_error"));
1546 /* Create the folder */
1547 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1548 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1550 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1553 /* Notify about operation end */
1554 modest_mail_operation_notify_end (self);
1560 modest_mail_operation_remove_folder (ModestMailOperation *self,
1562 gboolean remove_to_trash)
1564 TnyAccount *account;
1565 ModestMailOperationPrivate *priv;
1566 ModestTnyFolderRules rules;
1568 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1569 g_return_if_fail (TNY_IS_FOLDER (folder));
1571 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1573 /* Check folder rules */
1574 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1575 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1576 /* Set status failed and set an error */
1577 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1578 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1579 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1580 _("mail_in_ui_folder_delete_error"));
1584 /* Get the account */
1585 account = modest_tny_folder_get_account (folder);
1586 priv->account = g_object_ref(account);
1588 /* Delete folder or move to trash */
1589 if (remove_to_trash) {
1590 TnyFolder *trash_folder = NULL;
1591 trash_folder = modest_tny_account_get_special_folder (account,
1592 TNY_FOLDER_TYPE_TRASH);
1593 /* TODO: error_handling */
1595 modest_mail_operation_xfer_folder (self, folder,
1596 TNY_FOLDER_STORE (trash_folder),
1598 g_object_unref (trash_folder);
1601 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1603 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1604 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1607 g_object_unref (G_OBJECT (parent));
1609 g_object_unref (G_OBJECT (account));
1612 /* Notify about operation end */
1613 modest_mail_operation_notify_end (self);
1617 transfer_folder_status_cb (GObject *obj,
1621 ModestMailOperation *self;
1622 ModestMailOperationPrivate *priv;
1623 ModestMailOperationState *state;
1624 XFerMsgAsyncHelper *helper;
1626 g_return_if_fail (status != NULL);
1627 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1629 helper = (XFerMsgAsyncHelper *) user_data;
1630 g_return_if_fail (helper != NULL);
1632 self = helper->mail_op;
1633 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1635 priv->done = status->position;
1636 priv->total = status->of_total;
1638 state = modest_mail_operation_clone_state (self);
1639 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1640 gdk_threads_enter ();
1642 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1643 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1644 gdk_threads_leave ();
1646 g_slice_free (ModestMailOperationState, state);
1651 transfer_folder_cb (TnyFolder *folder,
1652 TnyFolderStore *into,
1654 TnyFolder *new_folder,
1658 XFerMsgAsyncHelper *helper;
1659 ModestMailOperation *self = NULL;
1660 ModestMailOperationPrivate *priv = NULL;
1662 helper = (XFerMsgAsyncHelper *) user_data;
1663 g_return_if_fail (helper != NULL);
1665 self = helper->mail_op;
1666 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1669 priv->error = g_error_copy (*err);
1671 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1672 } else if (cancelled) {
1673 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1674 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1675 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1676 _("Transference of %s was cancelled."),
1677 tny_folder_get_name (folder));
1680 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1683 /* Notify about operation end */
1684 modest_mail_operation_notify_end (self);
1686 /* If user defined callback function was defined, call it */
1687 if (helper->user_callback) {
1688 gdk_threads_enter ();
1689 helper->user_callback (priv->source, helper->user_data);
1690 gdk_threads_leave ();
1694 g_object_unref (helper->mail_op);
1695 g_slice_free (XFerMsgAsyncHelper, helper);
1700 * This function checks if the new name is a valid name for our local
1701 * folders account. The new name could not be the same than then name
1702 * of any of the mandatory local folders
1704 * We can not rely on tinymail because tinymail does not check the
1705 * name of the virtual folders that the account could have in the case
1706 * that we're doing a rename (because it directly calls Camel which
1707 * knows nothing about our virtual folders).
1709 * In the case of an actual copy/move (i.e. move/copy a folder between
1710 * accounts) tinymail uses the tny_folder_store_create_account which
1711 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1712 * checks the new name of the folder, so this call in that case
1713 * wouldn't be needed. *But* NOTE that if tinymail changes its
1714 * implementation (if folder transfers within the same account is no
1715 * longer implemented as a rename) this call will allow Modest to work
1718 * If the new name is not valid, this function will set the status to
1719 * failed and will set also an error in the mail operation
1722 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1723 TnyFolderStore *into,
1724 const gchar *new_name)
1726 if (TNY_IS_ACCOUNT (into) &&
1727 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1728 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1730 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1731 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1732 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1733 _("FIXME: folder name already in use"));
1740 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1742 TnyFolderStore *parent,
1743 gboolean delete_original,
1744 XferMsgsAsynUserCallback user_callback,
1747 ModestMailOperationPrivate *priv = NULL;
1748 ModestTnyFolderRules parent_rules = 0, rules;
1749 XFerMsgAsyncHelper *helper = NULL;
1751 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1752 g_return_if_fail (TNY_IS_FOLDER (folder));
1754 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1756 /* Get account and set it into mail_operation */
1757 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1758 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1760 /* Get folder rules */
1761 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1762 if (TNY_IS_FOLDER (parent))
1763 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1765 /* The moveable restriction is applied also to copy operation */
1766 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1767 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1768 /* Set status failed and set an error */
1769 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1770 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1771 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1772 _("mail_in_ui_folder_move_target_error"));
1774 /* Notify the queue */
1775 modest_mail_operation_notify_end (self);
1776 } else if (TNY_IS_FOLDER (parent) &&
1777 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1778 /* Set status failed and set an error */
1779 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1780 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1781 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1782 _("FIXME: parent folder does not accept new folders"));
1784 /* Notify the queue */
1785 modest_mail_operation_notify_end (self);
1789 /* Check that the new folder name is not used by any
1790 special local folder */
1791 if (new_name_valid_if_local_account (priv, parent,
1792 tny_folder_get_name (folder))) {
1793 /* Create the helper */
1794 helper = g_slice_new0 (XFerMsgAsyncHelper);
1795 helper->mail_op = g_object_ref(self);
1796 helper->dest_folder = NULL;
1797 helper->headers = NULL;
1798 helper->user_callback = user_callback;
1799 helper->user_data = user_data;
1801 /* Move/Copy folder */
1802 tny_folder_copy_async (folder,
1804 tny_folder_get_name (folder),
1807 transfer_folder_status_cb,
1810 modest_mail_operation_notify_end (self);
1816 modest_mail_operation_rename_folder (ModestMailOperation *self,
1820 ModestMailOperationPrivate *priv;
1821 ModestTnyFolderRules rules;
1822 XFerMsgAsyncHelper *helper;
1824 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1825 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1826 g_return_if_fail (name);
1828 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1830 /* Get account and set it into mail_operation */
1831 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1833 /* Check folder rules */
1834 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1835 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1836 /* Set status failed and set an error */
1837 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1838 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1839 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1840 _("FIXME: unable to rename"));
1842 /* Notify about operation end */
1843 modest_mail_operation_notify_end (self);
1844 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1845 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1846 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1847 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1848 _("FIXME: unable to rename"));
1849 /* Notify about operation end */
1850 modest_mail_operation_notify_end (self);
1852 TnyFolderStore *into;
1854 into = tny_folder_get_folder_store (folder);
1856 /* Check that the new folder name is not used by any
1857 special local folder */
1858 if (new_name_valid_if_local_account (priv, into, name)) {
1859 /* Create the helper */
1860 helper = g_slice_new0 (XFerMsgAsyncHelper);
1861 helper->mail_op = g_object_ref(self);
1862 helper->dest_folder = NULL;
1863 helper->headers = NULL;
1864 helper->user_callback = NULL;
1865 helper->user_data = NULL;
1867 /* Rename. Camel handles folder subscription/unsubscription */
1868 tny_folder_copy_async (folder, into, name, TRUE,
1870 transfer_folder_status_cb,
1873 modest_mail_operation_notify_end (self);
1875 g_object_unref (into);
1879 /* ******************************************************************* */
1880 /* ************************** MSG ACTIONS ************************* */
1881 /* ******************************************************************* */
1883 void modest_mail_operation_get_msg (ModestMailOperation *self,
1885 GetMsgAsyncUserCallback user_callback,
1888 GetMsgAsyncHelper *helper = NULL;
1890 ModestMailOperationPrivate *priv;
1892 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1893 g_return_if_fail (TNY_IS_HEADER (header));
1895 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1896 folder = tny_header_get_folder (header);
1898 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1900 /* Get message from folder */
1902 /* Get account and set it into mail_operation */
1903 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1905 helper = g_slice_new0 (GetMsgAsyncHelper);
1906 helper->mail_op = self;
1907 helper->user_callback = user_callback;
1908 helper->user_data = user_data;
1909 helper->header = g_object_ref (header);
1911 // The callback's reference so that the mail op is not
1912 // finalized until the async operation is completed even if
1913 // the user canceled the request meanwhile.
1914 g_object_ref (G_OBJECT (helper->mail_op));
1916 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1918 g_object_unref (G_OBJECT (folder));
1920 /* Set status failed and set an error */
1921 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1922 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1923 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1924 _("Error trying to get a message. No folder found for header"));
1926 /* Notify the queue */
1927 modest_mail_operation_notify_end (self);
1932 idle_get_mime_part_size_cb (gpointer userdata)
1934 GetMimePartSizeInfo *idle_info;
1936 idle_info = (GetMimePartSizeInfo *) userdata;
1938 gdk_threads_enter ();
1939 idle_info->callback (idle_info->mail_op,
1941 idle_info->userdata);
1942 gdk_threads_leave ();
1944 g_object_unref (idle_info->mail_op);
1945 g_slice_free (GetMimePartSizeInfo, idle_info);
1951 get_mime_part_size_thread (gpointer thr_user_data)
1953 GetMimePartSizeInfo *info;
1954 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1958 ModestMailOperationPrivate *priv;
1960 info = (GetMimePartSizeInfo *) thr_user_data;
1961 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1963 stream = tny_camel_mem_stream_new ();
1964 tny_mime_part_decode_to_stream (info->mime_part, stream);
1965 tny_stream_reset (stream);
1966 if (tny_stream_is_eos (stream)) {
1967 tny_stream_close (stream);
1968 stream = tny_mime_part_get_stream (info->mime_part);
1971 while (!tny_stream_is_eos (stream)) {
1972 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1973 total += readed_size;
1976 if (info->callback) {
1977 GetMimePartSizeInfo *idle_info;
1979 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1980 idle_info->mail_op = g_object_ref (info->mail_op);
1981 idle_info->size = total;
1982 idle_info->callback = info->callback;
1983 idle_info->userdata = info->userdata;
1984 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1987 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1989 g_object_unref (info->mail_op);
1990 g_object_unref (stream);
1991 g_object_unref (info->mime_part);
1992 g_slice_free (GetMimePartSizeInfo, info);
1998 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
2000 GetMimePartSizeCallback user_callback,
2002 GDestroyNotify notify)
2004 GetMimePartSizeInfo *info;
2005 ModestMailOperationPrivate *priv;
2008 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2009 g_return_if_fail (TNY_IS_MIME_PART (part));
2011 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2013 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2014 info = g_slice_new0 (GetMimePartSizeInfo);
2015 info->mail_op = g_object_ref (self);
2016 info->mime_part = g_object_ref (part);
2017 info->callback = user_callback;
2018 info->userdata = user_data;
2020 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2025 get_msg_cb (TnyFolder *folder,
2031 GetMsgAsyncHelper *helper = NULL;
2032 ModestMailOperation *self = NULL;
2033 ModestMailOperationPrivate *priv = NULL;
2035 helper = (GetMsgAsyncHelper *) user_data;
2036 g_return_if_fail (helper != NULL);
2037 self = helper->mail_op;
2038 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2039 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2041 /* Check errors and cancel */
2043 priv->error = g_error_copy (*error);
2044 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2045 } else if (cancelled) {
2046 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2047 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2048 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2049 _("Error trying to refresh the contents of %s"),
2050 tny_folder_get_name (folder));
2052 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2055 /* If user defined callback function was defined, call it even
2056 if the operation failed*/
2057 if (helper->user_callback) {
2058 /* This callback is called into an iddle by tinymail,
2059 and idles are not in the main lock */
2060 gdk_threads_enter ();
2061 helper->user_callback (self, helper->header, msg, helper->user_data);
2062 gdk_threads_leave ();
2065 /* Notify about operation end */
2066 modest_mail_operation_notify_end (self);
2068 g_object_unref (helper->mail_op);
2069 g_object_unref (helper->header);
2070 g_slice_free (GetMsgAsyncHelper, helper);
2075 get_msg_status_cb (GObject *obj,
2079 GetMsgAsyncHelper *helper = NULL;
2080 ModestMailOperation *self;
2081 ModestMailOperationPrivate *priv;
2082 ModestMailOperationState *state;
2084 g_return_if_fail (status != NULL);
2085 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2087 helper = (GetMsgAsyncHelper *) user_data;
2088 g_return_if_fail (helper != NULL);
2090 self = helper->mail_op;
2091 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2096 state = modest_mail_operation_clone_state (self);
2097 state->bytes_done = status->position;
2098 state->bytes_total = status->of_total;
2099 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2100 gdk_threads_enter ();
2102 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2103 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2104 gdk_threads_leave ();
2106 g_slice_free (ModestMailOperationState, state);
2109 /****************************************************/
2111 ModestMailOperation *mail_op;
2113 GetMsgAsyncUserCallback user_callback;
2115 GDestroyNotify notify;
2119 GetMsgAsyncUserCallback user_callback;
2123 ModestMailOperation *mail_op;
2124 } NotifyGetMsgsInfo;
2128 * Used by get_msgs_full_thread to call the user_callback for each
2129 * message that has been read
2132 notify_get_msgs_full (gpointer data)
2134 NotifyGetMsgsInfo *info;
2136 info = (NotifyGetMsgsInfo *) data;
2138 /* Call the user callback. Idles are not in the main lock, so
2140 gdk_threads_enter ();
2141 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2142 gdk_threads_leave ();
2144 g_slice_free (NotifyGetMsgsInfo, info);
2150 * Used by get_msgs_full_thread to free al the thread resources and to
2151 * call the destroy function for the passed user_data
2154 get_msgs_full_destroyer (gpointer data)
2156 GetFullMsgsInfo *info;
2158 info = (GetFullMsgsInfo *) data;
2161 gdk_threads_enter ();
2162 info->notify (info->user_data);
2163 gdk_threads_leave ();
2167 g_object_unref (info->headers);
2168 g_slice_free (GetFullMsgsInfo, info);
2174 get_msgs_full_thread (gpointer thr_user_data)
2176 GetFullMsgsInfo *info;
2177 ModestMailOperationPrivate *priv = NULL;
2178 TnyIterator *iter = NULL;
2180 info = (GetFullMsgsInfo *) thr_user_data;
2181 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2183 iter = tny_list_create_iterator (info->headers);
2184 while (!tny_iterator_is_done (iter)) {
2188 header = TNY_HEADER (tny_iterator_get_current (iter));
2189 folder = tny_header_get_folder (header);
2191 /* Get message from folder */
2194 /* The callback will call it per each header */
2195 msg = tny_folder_get_msg (folder, header, &(priv->error));
2198 ModestMailOperationState *state;
2203 /* notify progress */
2204 state = modest_mail_operation_clone_state (info->mail_op);
2205 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2206 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2207 pair, (GDestroyNotify) modest_pair_free);
2209 /* The callback is the responsible for
2210 freeing the message */
2211 if (info->user_callback) {
2212 NotifyGetMsgsInfo *info_notify;
2213 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2214 info_notify->user_callback = info->user_callback;
2215 info_notify->mail_op = info->mail_op;
2216 info_notify->header = g_object_ref (header);
2217 info_notify->msg = g_object_ref (msg);
2218 info_notify->user_data = info->user_data;
2219 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2220 notify_get_msgs_full,
2223 g_object_unref (msg);
2226 /* Set status failed and set an error */
2227 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2228 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2229 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2230 "Error trying to get a message. No folder found for header");
2234 g_object_unref (header);
2236 tny_iterator_next (iter);
2239 /* Set operation status */
2240 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2241 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2243 /* Notify about operation end */
2244 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2246 /* Free thread resources. Will be called after all previous idles */
2247 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2253 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2254 TnyList *header_list,
2255 GetMsgAsyncUserCallback user_callback,
2257 GDestroyNotify notify)
2259 TnyHeader *header = NULL;
2260 TnyFolder *folder = NULL;
2262 ModestMailOperationPrivate *priv = NULL;
2263 GetFullMsgsInfo *info = NULL;
2264 gboolean size_ok = TRUE;
2266 TnyIterator *iter = NULL;
2268 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2270 /* Init mail operation */
2271 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2272 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2274 priv->total = tny_list_get_length(header_list);
2276 /* Get account and set it into mail_operation */
2277 if (tny_list_get_length (header_list) >= 1) {
2278 iter = tny_list_create_iterator (header_list);
2279 header = TNY_HEADER (tny_iterator_get_current (iter));
2281 folder = tny_header_get_folder (header);
2283 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2285 g_object_unref (folder);
2288 g_object_unref (header);
2291 if (tny_list_get_length (header_list) == 1) {
2292 g_object_unref (iter);
2297 /* Get msg size limit */
2298 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2299 MODEST_CONF_MSG_SIZE_LIMIT,
2302 g_clear_error (&(priv->error));
2303 max_size = G_MAXINT;
2305 max_size = max_size * KB;
2308 /* Check message size limits. If there is only one message
2309 always retrieve it */
2311 while (!tny_iterator_is_done (iter) && size_ok) {
2312 header = TNY_HEADER (tny_iterator_get_current (iter));
2314 if (tny_header_get_message_size (header) >= max_size)
2316 g_object_unref (header);
2319 tny_iterator_next (iter);
2321 g_object_unref (iter);
2325 /* Create the info */
2326 info = g_slice_new0 (GetFullMsgsInfo);
2327 info->mail_op = self;
2328 info->user_callback = user_callback;
2329 info->user_data = user_data;
2330 info->headers = g_object_ref (header_list);
2331 info->notify = notify;
2333 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2335 /* Set status failed and set an error */
2336 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2337 /* FIXME: the error msg is different for pop */
2338 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2339 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2340 _("emev_ni_ui_imap_msg_size_exceed_error"));
2341 /* Remove from queue and free resources */
2342 modest_mail_operation_notify_end (self);
2350 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2351 gboolean remove_to_trash /*ignored*/)
2354 ModestMailOperationPrivate *priv;
2356 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2357 g_return_if_fail (TNY_IS_HEADER (header));
2359 if (remove_to_trash)
2360 g_warning ("remove to trash is not implemented");
2362 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2363 folder = tny_header_get_folder (header);
2365 /* Get account and set it into mail_operation */
2366 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2368 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2371 tny_folder_remove_msg (folder, header, &(priv->error));
2373 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2374 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2376 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2377 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2378 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2379 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2382 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2388 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2390 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2393 g_object_unref (G_OBJECT (folder));
2395 /* Notify about operation end */
2396 modest_mail_operation_notify_end (self);
2400 transfer_msgs_status_cb (GObject *obj,
2404 XFerMsgAsyncHelper *helper = NULL;
2405 ModestMailOperation *self;
2406 ModestMailOperationPrivate *priv;
2407 ModestMailOperationState *state;
2410 g_return_if_fail (status != NULL);
2411 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2413 helper = (XFerMsgAsyncHelper *) user_data;
2414 g_return_if_fail (helper != NULL);
2416 self = helper->mail_op;
2417 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2419 priv->done = status->position;
2420 priv->total = status->of_total;
2422 state = modest_mail_operation_clone_state (self);
2423 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2424 gdk_threads_enter ();
2426 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2427 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2428 gdk_threads_leave ();
2430 g_slice_free (ModestMailOperationState, state);
2435 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2437 XFerMsgAsyncHelper *helper;
2438 ModestMailOperation *self;
2439 ModestMailOperationPrivate *priv;
2441 helper = (XFerMsgAsyncHelper *) user_data;
2442 self = helper->mail_op;
2444 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2447 priv->error = g_error_copy (*err);
2449 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2450 } else if (cancelled) {
2451 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2452 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2453 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2454 _("Error trying to refresh the contents of %s"),
2455 tny_folder_get_name (folder));
2458 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2461 /* Notify about operation end */
2462 modest_mail_operation_notify_end (self);
2464 /* If user defined callback function was defined, call it */
2465 if (helper->user_callback) {
2466 gdk_threads_enter ();
2467 helper->user_callback (priv->source, helper->user_data);
2468 gdk_threads_leave ();
2472 g_object_unref (helper->headers);
2473 g_object_unref (helper->dest_folder);
2474 g_object_unref (helper->mail_op);
2475 g_slice_free (XFerMsgAsyncHelper, helper);
2476 g_object_unref (folder);
2481 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2484 gboolean delete_original,
2485 XferMsgsAsynUserCallback user_callback,
2488 ModestMailOperationPrivate *priv = NULL;
2489 TnyIterator *iter = NULL;
2490 TnyFolder *src_folder = NULL;
2491 XFerMsgAsyncHelper *helper = NULL;
2492 TnyHeader *header = NULL;
2493 ModestTnyFolderRules rules = 0;
2494 const gchar *id1 = NULL;
2495 const gchar *id2 = NULL;
2496 gboolean same_folder = FALSE;
2498 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2499 g_return_if_fail (TNY_IS_LIST (headers));
2500 g_return_if_fail (TNY_IS_FOLDER (folder));
2502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2505 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2507 /* Apply folder rules */
2508 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2509 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2510 /* Set status failed and set an error */
2511 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2512 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2513 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2514 _CS("ckct_ib_unable_to_paste_here"));
2515 /* Notify the queue */
2516 modest_mail_operation_notify_end (self);
2520 /* Get source folder */
2521 iter = tny_list_create_iterator (headers);
2522 header = TNY_HEADER (tny_iterator_get_current (iter));
2524 src_folder = tny_header_get_folder (header);
2525 g_object_unref (header);
2528 g_object_unref (iter);
2530 /* Check folder source and destination */
2531 id1 = tny_folder_get_id (src_folder);
2532 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2533 same_folder = !g_ascii_strcasecmp (id1, id2);
2535 /* Set status failed and set an error */
2536 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2537 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2538 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2539 _("mcen_ib_unable_to_copy_samefolder"));
2541 /* Notify the queue */
2542 modest_mail_operation_notify_end (self);
2545 g_object_unref (src_folder);
2549 /* Create the helper */
2550 helper = g_slice_new0 (XFerMsgAsyncHelper);
2551 helper->mail_op = g_object_ref(self);
2552 helper->dest_folder = g_object_ref(folder);
2553 helper->headers = g_object_ref(headers);
2554 helper->user_callback = user_callback;
2555 helper->user_data = user_data;
2557 /* Get account and set it into mail_operation */
2558 priv->account = modest_tny_folder_get_account (src_folder);
2560 /* Transfer messages */
2561 tny_folder_transfer_msgs_async (src_folder,
2566 transfer_msgs_status_cb,
2572 on_refresh_folder (TnyFolder *folder,
2577 RefreshAsyncHelper *helper = NULL;
2578 ModestMailOperation *self = NULL;
2579 ModestMailOperationPrivate *priv = NULL;
2581 helper = (RefreshAsyncHelper *) user_data;
2582 self = helper->mail_op;
2583 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2586 priv->error = g_error_copy (*error);
2587 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2592 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2593 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2594 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2595 _("Error trying to refresh the contents of %s"),
2596 tny_folder_get_name (folder));
2600 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2602 /* Call user defined callback, if it exists */
2603 if (helper->user_callback) {
2604 gdk_threads_enter ();
2605 helper->user_callback (self, folder, helper->user_data);
2606 gdk_threads_leave ();
2610 /* g_object_unref (helper->mail_op); */
2611 g_slice_free (RefreshAsyncHelper, helper);
2613 /* Notify about operation end */
2614 modest_mail_operation_notify_end (self);
2618 on_refresh_folder_status_update (GObject *obj,
2622 RefreshAsyncHelper *helper = NULL;
2623 ModestMailOperation *self = NULL;
2624 ModestMailOperationPrivate *priv = NULL;
2625 ModestMailOperationState *state;
2627 g_return_if_fail (user_data != NULL);
2628 g_return_if_fail (status != NULL);
2629 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2631 helper = (RefreshAsyncHelper *) user_data;
2632 self = helper->mail_op;
2633 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2635 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2637 priv->done = status->position;
2638 priv->total = status->of_total;
2640 state = modest_mail_operation_clone_state (self);
2641 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2642 gdk_threads_enter ();
2644 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2645 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2646 gdk_threads_leave ();
2648 g_slice_free (ModestMailOperationState, state);
2652 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2654 RefreshAsyncUserCallback user_callback,
2657 ModestMailOperationPrivate *priv = NULL;
2658 RefreshAsyncHelper *helper = NULL;
2660 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2662 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2664 /* Get account and set it into mail_operation */
2665 priv->account = modest_tny_folder_get_account (folder);
2667 /* Create the helper */
2668 helper = g_slice_new0 (RefreshAsyncHelper);
2669 helper->mail_op = g_object_ref (self);
2670 helper->user_callback = user_callback;
2671 helper->user_data = user_data;
2673 /* Refresh the folder. TODO: tinymail could issue a status
2674 updates before the callback call then this could happen. We
2675 must review the design */
2676 tny_folder_refresh_async (folder,
2678 on_refresh_folder_status_update,
2684 * It's used by the mail operation queue to notify the observers
2685 * attached to that signal that the operation finished. We need to use
2686 * that because tinymail does not give us the progress of a given
2687 * operation when it finishes (it directly calls the operation
2691 modest_mail_operation_notify_end (ModestMailOperation *self)
2693 ModestMailOperationState *state;
2694 ModestMailOperationPrivate *priv = NULL;
2696 g_return_if_fail (self);
2698 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2700 /* Set the account back to not busy */
2701 if (priv->account_name) {
2702 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2703 priv->account_name, FALSE);
2704 g_free(priv->account_name);
2705 priv->account_name = NULL;
2708 /* Notify the observers about the mail operation end */
2709 /* We do not wrapp this emission because we assume that this
2710 function is always called from within the main lock */
2711 state = modest_mail_operation_clone_state (self);
2712 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2713 g_slice_free (ModestMailOperationState, state);