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);
725 g_object_unref (info->draft_msg);
726 if (info->transport_account)
727 g_object_unref (info->transport_account);
728 g_slice_free (SendNewMailInfo, info);
729 modest_mail_operation_notify_end (self);
733 modest_mail_operation_send_new_mail (ModestMailOperation *self,
734 TnyTransportAccount *transport_account,
736 const gchar *from, const gchar *to,
737 const gchar *cc, const gchar *bcc,
738 const gchar *subject, const gchar *plain_body,
739 const gchar *html_body,
740 const GList *attachments_list,
741 TnyHeaderFlags priority_flags)
743 ModestMailOperationPrivate *priv = NULL;
744 SendNewMailInfo *info;
746 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
747 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
749 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
751 /* Check parametters */
753 /* Set status failed and set an error */
754 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
755 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
756 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
757 _("Error trying to send a mail. You need to set at least one recipient"));
760 info = g_slice_new0 (SendNewMailInfo);
761 info->transport_account = transport_account;
762 if (transport_account)
763 g_object_ref (transport_account);
764 info->draft_msg = draft_msg;
766 g_object_ref (draft_msg);
767 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
768 attachments_list, priority_flags,
769 modest_mail_operation_send_new_mail_cb, info);
775 TnyTransportAccount *transport_account;
777 ModestMsgEditWindow *edit_window;
781 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
785 TnyFolder *folder = NULL;
786 TnyHeader *header = NULL;
787 ModestMailOperationPrivate *priv = NULL;
788 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
790 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
792 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
793 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
794 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
795 "modest: failed to create a new msg\n");
799 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
801 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
802 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
803 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
804 "modest: failed to create a new msg\n");
808 if (info->draft_msg != NULL) {
809 header = tny_msg_get_header (info->draft_msg);
810 /* Remove the old draft expunging it */
811 tny_folder_remove_msg (folder, header, NULL);
812 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
813 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
814 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
815 g_object_unref (header);
819 tny_folder_add_msg (folder, msg, &(priv->error));
822 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
824 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
826 if (info->edit_window)
827 modest_msg_edit_window_set_draft (info->edit_window, msg);
832 g_object_unref (G_OBJECT(folder));
833 if (info->edit_window)
834 g_object_unref (G_OBJECT(info->edit_window));
836 g_object_unref (G_OBJECT (info->draft_msg));
837 if (info->transport_account)
838 g_object_unref (G_OBJECT(info->transport_account));
839 g_slice_free (SaveToDraftsInfo, info);
841 modest_mail_operation_notify_end (self);
845 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
846 TnyTransportAccount *transport_account,
848 ModestMsgEditWindow *edit_window,
849 const gchar *from, const gchar *to,
850 const gchar *cc, const gchar *bcc,
851 const gchar *subject, const gchar *plain_body,
852 const gchar *html_body,
853 const GList *attachments_list,
854 TnyHeaderFlags priority_flags)
856 ModestMailOperationPrivate *priv = NULL;
857 SaveToDraftsInfo *info = NULL;
859 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
860 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
862 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
864 /* Get account and set it into mail_operation */
865 priv->account = g_object_ref (transport_account);
867 info = g_slice_new0 (SaveToDraftsInfo);
868 info->transport_account = g_object_ref (transport_account);
869 info->draft_msg = draft_msg;
871 g_object_ref (draft_msg);
872 info->edit_window = edit_window;
874 g_object_ref (edit_window);
876 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
877 attachments_list, priority_flags,
878 modest_mail_operation_save_to_drafts_cb, info);
884 ModestMailOperation *mail_op;
885 TnyStoreAccount *account;
886 TnyTransportAccount *transport_account;
889 gchar *retrieve_type;
891 UpdateAccountCallback callback;
898 ModestMailOperation *mail_op;
899 TnyMimePart *mime_part;
901 GetMimePartSizeCallback callback;
903 } GetMimePartSizeInfo;
905 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
906 /* We use this folder observer to track the headers that have been
907 * added to a folder */
910 TnyList *new_headers;
911 } InternalFolderObserver;
915 } InternalFolderObserverClass;
917 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
919 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
920 internal_folder_observer,
922 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
926 foreach_add_item (gpointer header, gpointer user_data)
928 tny_list_prepend (TNY_LIST (user_data),
929 g_object_ref (G_OBJECT (header)));
932 /* This is the method that looks for new messages in a folder */
934 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
936 InternalFolderObserver *derived = (InternalFolderObserver *)self;
938 TnyFolderChangeChanged changed;
940 changed = tny_folder_change_get_changed (change);
942 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
945 /* Get added headers */
946 list = tny_simple_list_new ();
947 tny_folder_change_get_added_headers (change, list);
949 /* Add them to the folder observer */
950 tny_list_foreach (list, foreach_add_item,
951 derived->new_headers);
953 g_object_unref (G_OBJECT (list));
958 internal_folder_observer_init (InternalFolderObserver *self)
960 self->new_headers = tny_simple_list_new ();
963 internal_folder_observer_finalize (GObject *object)
965 InternalFolderObserver *self;
967 self = (InternalFolderObserver *) object;
968 g_object_unref (self->new_headers);
970 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
973 tny_folder_observer_init (TnyFolderObserverIface *iface)
975 iface->update_func = internal_folder_observer_update;
978 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
980 GObjectClass *object_class;
982 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
983 object_class = (GObjectClass*) klass;
984 object_class->finalize = internal_folder_observer_finalize;
990 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
993 TnyList *folders = tny_simple_list_new ();
995 tny_folder_store_get_folders (store, folders, query, NULL);
996 iter = tny_list_create_iterator (folders);
998 while (!tny_iterator_is_done (iter)) {
1000 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1002 tny_list_prepend (all_folders, G_OBJECT (folder));
1003 recurse_folders (folder, query, all_folders);
1004 g_object_unref (G_OBJECT (folder));
1006 tny_iterator_next (iter);
1008 g_object_unref (G_OBJECT (iter));
1009 g_object_unref (G_OBJECT (folders));
1013 * Issues the "progress-changed" signal. The timer won't be removed,
1014 * so you must call g_source_remove to stop the signal emission
1017 idle_notify_progress (gpointer data)
1019 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1020 ModestMailOperationState *state;
1022 state = modest_mail_operation_clone_state (mail_op);
1023 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1024 gdk_threads_enter ();
1026 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1027 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1028 gdk_threads_leave ();
1030 g_slice_free (ModestMailOperationState, state);
1036 * Issues the "progress-changed" signal and removes the timer. It uses
1037 * a lock to ensure that the progress information of the mail
1038 * operation is not modified while there are notifications pending
1041 idle_notify_progress_once (gpointer data)
1045 pair = (ModestPair *) data;
1047 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1048 gdk_threads_enter ();
1050 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1051 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1052 gdk_threads_leave ();
1055 /* Free the state and the reference to the mail operation */
1056 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1057 g_object_unref (pair->first);
1063 * Used to notify the queue from the main
1064 * loop. We call it inside an idle call to achieve that
1067 idle_notify_queue (gpointer data)
1069 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1071 /* Do not need to block, the notify end will do it for us */
1072 modest_mail_operation_notify_end (mail_op);
1073 g_object_unref (mail_op);
1079 compare_headers_by_date (gconstpointer a,
1082 TnyHeader **header1, **header2;
1083 time_t sent1, sent2;
1085 header1 = (TnyHeader **) a;
1086 header2 = (TnyHeader **) b;
1088 sent1 = tny_header_get_date_sent (*header1);
1089 sent2 = tny_header_get_date_sent (*header2);
1091 /* We want the most recent ones (greater time_t) at the
1100 set_last_updated_idle (gpointer data)
1102 gdk_threads_enter ();
1104 /* It does not matter if the time is not exactly the same than
1105 the time when this idle was called, it's just an
1106 approximation and it won't be very different */
1107 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1109 MODEST_ACCOUNT_LAST_UPDATED,
1113 gdk_threads_leave ();
1119 idle_update_account_cb (gpointer data)
1121 UpdateAccountInfo *idle_info;
1123 idle_info = (UpdateAccountInfo *) data;
1125 gdk_threads_enter ();
1126 idle_info->callback (idle_info->mail_op,
1127 idle_info->new_headers,
1128 idle_info->user_data);
1129 gdk_threads_leave ();
1132 g_object_unref (idle_info->mail_op);
1140 update_account_thread (gpointer thr_user_data)
1142 static gboolean first_time = TRUE;
1143 UpdateAccountInfo *info = NULL;
1144 TnyList *all_folders = NULL;
1145 GPtrArray *new_headers = NULL;
1146 TnyIterator *iter = NULL;
1147 TnyFolderStoreQuery *query = NULL;
1148 ModestMailOperationPrivate *priv = NULL;
1149 ModestTnySendQueue *send_queue = NULL;
1150 gint num_new_headers = 0;
1152 info = (UpdateAccountInfo *) thr_user_data;
1153 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1155 /* Get account and set it into mail_operation */
1156 priv->account = g_object_ref (info->account);
1159 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1160 * show any updates unless we do that
1162 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1163 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1165 /* Get all the folders. We can do it synchronously because
1166 we're already running in a different thread than the UI */
1167 all_folders = tny_simple_list_new ();
1168 query = tny_folder_store_query_new ();
1169 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1170 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1175 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1179 iter = tny_list_create_iterator (all_folders);
1180 while (!tny_iterator_is_done (iter)) {
1181 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1183 recurse_folders (folder, query, all_folders);
1184 tny_iterator_next (iter);
1186 g_object_unref (G_OBJECT (iter));
1188 /* Update status and notify. We need to call the notification
1189 with a source function in order to call it from the main
1190 loop. We need that in order not to get into trouble with
1191 Gtk+. We use a timeout in order to provide more status
1192 information, because the sync tinymail call does not
1193 provide it for the moment */
1194 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1196 /* Refresh folders */
1197 num_new_headers = 0;
1198 new_headers = g_ptr_array_new ();
1199 iter = tny_list_create_iterator (all_folders);
1201 while (!tny_iterator_is_done (iter) && !priv->error &&
1202 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1204 InternalFolderObserver *observer;
1205 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1207 /* Refresh the folder */
1208 /* Our observer receives notification of new emails during folder refreshes,
1209 * so we can use observer->new_headers.
1211 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1212 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1214 /* This gets the status information (headers) from the server.
1215 * We use the blocking version, because we are already in a separate
1219 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1220 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1223 /* If the retrieve type is full messages, refresh and get the messages */
1224 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1226 iter = tny_list_create_iterator (observer->new_headers);
1227 while (!tny_iterator_is_done (iter)) {
1228 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1230 /* Apply per-message size limits */
1231 if (tny_header_get_message_size (header) < info->max_size)
1232 g_ptr_array_add (new_headers, g_object_ref (header));
1234 g_object_unref (header);
1235 tny_iterator_next (iter);
1237 g_object_unref (iter);
1239 /* We do not need to do it the first time
1240 because it's automatically done by the tree
1242 if (G_UNLIKELY (!first_time))
1243 tny_folder_poke_status (TNY_FOLDER (folder));
1245 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1246 g_object_unref (observer);
1249 g_object_unref (G_OBJECT (folder));
1251 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1253 tny_iterator_next (iter);
1256 g_object_unref (G_OBJECT (iter));
1257 g_source_remove (timeout);
1259 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1260 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1261 new_headers->len > 0) {
1265 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1267 /* Apply message count limit */
1268 /* If the number of messages exceeds the maximum, ask the
1269 * user to download them all,
1270 * as per the UI spec "Retrieval Limits" section in 4.4:
1272 if (new_headers->len > info->retrieve_limit) {
1273 /* TODO: Ask the user, instead of just
1275 * mail_nc_msg_count_limit_exceeded, with 'Get
1276 * all' and 'Newest only' buttons. */
1277 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1278 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1279 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1280 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1281 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1286 priv->total = MIN (new_headers->len, info->retrieve_limit);
1287 while (msg_num < priv->total) {
1289 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1290 TnyFolder *folder = tny_header_get_folder (header);
1291 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1292 ModestMailOperationState *state;
1296 /* We can not just use the mail operation because the
1297 values of done and total could change before the
1299 state = modest_mail_operation_clone_state (info->mail_op);
1300 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1301 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1302 pair, (GDestroyNotify) modest_pair_free);
1304 g_object_unref (msg);
1305 g_object_unref (folder);
1311 /* Get the number of new headers and free them */
1312 num_new_headers = new_headers->len;
1313 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1314 g_ptr_array_free (new_headers, FALSE);
1316 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1319 /* Perform send (if operation was not cancelled) */
1320 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1323 if (priv->account != NULL)
1324 g_object_unref (priv->account);
1325 priv->account = g_object_ref (info->transport_account);
1327 send_queue = modest_runtime_get_send_queue (info->transport_account);
1329 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1330 modest_tny_send_queue_try_to_send (send_queue);
1331 /* g_source_remove (timeout); */
1333 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1334 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1335 "cannot create a send queue for %s\n",
1336 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1337 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1340 /* Check if the operation was a success */
1342 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1344 /* Update the last updated key */
1345 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1346 set_last_updated_idle,
1347 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1348 (GDestroyNotify) g_free);
1353 if (info->callback) {
1354 UpdateAccountInfo *idle_info;
1356 /* This thread is not in the main lock */
1357 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1358 idle_info->mail_op = g_object_ref (info->mail_op);
1359 idle_info->new_headers = num_new_headers;
1360 idle_info->callback = info->callback;
1361 g_idle_add (idle_update_account_cb, idle_info);
1364 /* Notify about operation end. Note that the info could be
1365 freed before this idle happens, but the mail operation will
1367 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1370 g_object_unref (query);
1371 g_object_unref (all_folders);
1372 g_object_unref (info->account);
1373 g_object_unref (info->transport_account);
1374 g_free (info->retrieve_type);
1375 g_slice_free (UpdateAccountInfo, info);
1383 modest_mail_operation_update_account (ModestMailOperation *self,
1384 const gchar *account_name,
1385 UpdateAccountCallback callback,
1388 GThread *thread = NULL;
1389 UpdateAccountInfo *info = NULL;
1390 ModestMailOperationPrivate *priv = NULL;
1391 ModestAccountMgr *mgr = NULL;
1392 TnyStoreAccount *store_account = NULL;
1393 TnyTransportAccount *transport_account = NULL;
1395 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1396 g_return_val_if_fail (account_name, FALSE);
1398 /* Init mail operation. Set total and done to 0, and do not
1399 update them, this way the progress objects will know that
1400 we have no clue about the number of the objects */
1401 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1404 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1406 /* Get the Modest account */
1407 store_account = (TnyStoreAccount *)
1408 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1410 TNY_ACCOUNT_TYPE_STORE);
1412 /* Make sure that we have a connection, and request one
1414 * TODO: Is there some way to trigger this for every attempt to
1415 * use the network? */
1416 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1419 if (!store_account) {
1420 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1421 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1422 "cannot get tny store account for %s\n", account_name);
1427 /* Get the transport account, we can not do it in the thread
1428 due to some problems with dbus */
1429 transport_account = (TnyTransportAccount *)
1430 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1432 if (!transport_account) {
1433 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1434 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1435 "cannot get tny transport account for %s\n", account_name);
1439 /* Create the helper object */
1440 info = g_slice_new (UpdateAccountInfo);
1441 info->mail_op = self;
1442 info->account = store_account;
1443 info->transport_account = transport_account;
1444 info->callback = callback;
1445 info->user_data = user_data;
1447 /* Get the message size limit */
1448 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1449 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1450 if (info->max_size == 0)
1451 info->max_size = G_MAXINT;
1453 info->max_size = info->max_size * KB;
1455 /* Get per-account retrieval type */
1456 mgr = modest_runtime_get_account_mgr ();
1457 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1458 MODEST_ACCOUNT_RETRIEVE, FALSE);
1460 /* Get per-account message amount retrieval limit */
1461 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1462 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1463 if (info->retrieve_limit == 0)
1464 info->retrieve_limit = G_MAXINT;
1466 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1468 /* Set account busy */
1469 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1470 priv->account_name = g_strdup(account_name);
1472 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1477 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1479 callback (self, 0, user_data);
1480 modest_mail_operation_notify_end (self);
1484 /* ******************************************************************* */
1485 /* ************************** STORE ACTIONS ************************* */
1486 /* ******************************************************************* */
1490 modest_mail_operation_create_folder (ModestMailOperation *self,
1491 TnyFolderStore *parent,
1494 ModestMailOperationPrivate *priv;
1495 TnyFolder *new_folder = NULL;
1497 TnyList *list = tny_simple_list_new ();
1498 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1500 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1501 g_return_val_if_fail (name, NULL);
1503 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1505 /* Check for already existing folder */
1506 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1507 tny_folder_store_get_folders (parent, list, query, NULL);
1508 g_object_unref (G_OBJECT (query));
1510 if (tny_list_get_length (list) > 0) {
1511 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1512 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1513 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1514 _CS("ckdg_ib_folder_already_exists"));
1517 g_object_unref (G_OBJECT (list));
1520 if (TNY_IS_FOLDER (parent)) {
1521 /* Check folder rules */
1522 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1523 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1524 /* Set status failed and set an error */
1525 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1526 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1527 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1528 _("mail_in_ui_folder_create_error"));
1532 if (!strcmp (name, " ") || strchr (name, '/')) {
1533 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1534 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1535 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1536 _("mail_in_ui_folder_create_error"));
1540 /* Create the folder */
1541 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1542 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1544 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1547 /* Notify about operation end */
1548 modest_mail_operation_notify_end (self);
1554 modest_mail_operation_remove_folder (ModestMailOperation *self,
1556 gboolean remove_to_trash)
1558 TnyAccount *account;
1559 ModestMailOperationPrivate *priv;
1560 ModestTnyFolderRules rules;
1562 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1563 g_return_if_fail (TNY_IS_FOLDER (folder));
1565 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1567 /* Check folder rules */
1568 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1569 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1570 /* Set status failed and set an error */
1571 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1572 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1573 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1574 _("mail_in_ui_folder_delete_error"));
1578 /* Get the account */
1579 account = modest_tny_folder_get_account (folder);
1580 priv->account = g_object_ref(account);
1582 /* Delete folder or move to trash */
1583 if (remove_to_trash) {
1584 TnyFolder *trash_folder = NULL;
1585 trash_folder = modest_tny_account_get_special_folder (account,
1586 TNY_FOLDER_TYPE_TRASH);
1587 /* TODO: error_handling */
1588 modest_mail_operation_xfer_folder (self, folder,
1589 TNY_FOLDER_STORE (trash_folder),
1592 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1594 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1595 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1598 g_object_unref (G_OBJECT (parent));
1600 g_object_unref (G_OBJECT (account));
1603 /* Notify about operation end */
1604 modest_mail_operation_notify_end (self);
1608 transfer_folder_status_cb (GObject *obj,
1612 ModestMailOperation *self;
1613 ModestMailOperationPrivate *priv;
1614 ModestMailOperationState *state;
1615 XFerMsgAsyncHelper *helper;
1617 g_return_if_fail (status != NULL);
1618 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1620 helper = (XFerMsgAsyncHelper *) user_data;
1621 g_return_if_fail (helper != NULL);
1623 self = helper->mail_op;
1624 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1626 priv->done = status->position;
1627 priv->total = status->of_total;
1629 state = modest_mail_operation_clone_state (self);
1630 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1631 gdk_threads_enter ();
1633 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1634 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1635 gdk_threads_leave ();
1637 g_slice_free (ModestMailOperationState, state);
1642 transfer_folder_cb (TnyFolder *folder,
1643 TnyFolderStore *into,
1645 TnyFolder *new_folder,
1649 XFerMsgAsyncHelper *helper;
1650 ModestMailOperation *self = NULL;
1651 ModestMailOperationPrivate *priv = NULL;
1653 helper = (XFerMsgAsyncHelper *) user_data;
1654 g_return_if_fail (helper != NULL);
1656 self = helper->mail_op;
1657 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1660 priv->error = g_error_copy (*err);
1662 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1663 } else if (cancelled) {
1664 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1665 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1666 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1667 _("Transference of %s was cancelled."),
1668 tny_folder_get_name (folder));
1671 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1674 /* Notify about operation end */
1675 modest_mail_operation_notify_end (self);
1677 /* If user defined callback function was defined, call it */
1678 if (helper->user_callback) {
1679 gdk_threads_enter ();
1680 helper->user_callback (priv->source, helper->user_data);
1681 gdk_threads_leave ();
1685 g_object_unref (helper->mail_op);
1686 g_slice_free (XFerMsgAsyncHelper, helper);
1691 * This function checks if the new name is a valid name for our local
1692 * folders account. The new name could not be the same than then name
1693 * of any of the mandatory local folders
1695 * We can not rely on tinymail because tinymail does not check the
1696 * name of the virtual folders that the account could have in the case
1697 * that we're doing a rename (because it directly calls Camel which
1698 * knows nothing about our virtual folders).
1700 * In the case of an actual copy/move (i.e. move/copy a folder between
1701 * accounts) tinymail uses the tny_folder_store_create_account which
1702 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1703 * checks the new name of the folder, so this call in that case
1704 * wouldn't be needed. *But* NOTE that if tinymail changes its
1705 * implementation (if folder transfers within the same account is no
1706 * longer implemented as a rename) this call will allow Modest to work
1709 * If the new name is not valid, this function will set the status to
1710 * failed and will set also an error in the mail operation
1713 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1714 TnyFolderStore *into,
1715 const gchar *new_name)
1717 if (TNY_IS_ACCOUNT (into) &&
1718 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1719 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1721 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1722 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1723 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1724 _("FIXME: folder name already in use"));
1731 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1733 TnyFolderStore *parent,
1734 gboolean delete_original,
1735 XferMsgsAsynUserCallback user_callback,
1738 ModestMailOperationPrivate *priv = NULL;
1739 ModestTnyFolderRules parent_rules = 0, rules;
1740 XFerMsgAsyncHelper *helper = NULL;
1742 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1743 g_return_if_fail (TNY_IS_FOLDER (folder));
1745 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1747 /* Get account and set it into mail_operation */
1748 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1749 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1751 /* Get folder rules */
1752 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1753 if (TNY_IS_FOLDER (parent))
1754 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1756 /* The moveable restriction is applied also to copy operation */
1757 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1758 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1759 /* Set status failed and set an error */
1760 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1761 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1762 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1763 _("mail_in_ui_folder_move_target_error"));
1765 /* Notify the queue */
1766 modest_mail_operation_notify_end (self);
1767 } else if (TNY_IS_FOLDER (parent) &&
1768 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
1769 /* Set status failed and set an error */
1770 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1771 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1772 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1773 _("FIXME: parent folder does not accept new folders"));
1775 /* Notify the queue */
1776 modest_mail_operation_notify_end (self);
1780 /* Check that the new folder name is not used by any
1781 special local folder */
1782 if (new_name_valid_if_local_account (priv, parent,
1783 tny_folder_get_name (folder))) {
1784 /* Create the helper */
1785 helper = g_slice_new0 (XFerMsgAsyncHelper);
1786 helper->mail_op = g_object_ref(self);
1787 helper->dest_folder = NULL;
1788 helper->headers = NULL;
1789 helper->user_callback = user_callback;
1790 helper->user_data = user_data;
1792 /* Move/Copy folder */
1793 tny_folder_copy_async (folder,
1795 tny_folder_get_name (folder),
1798 transfer_folder_status_cb,
1801 modest_mail_operation_notify_end (self);
1807 modest_mail_operation_rename_folder (ModestMailOperation *self,
1811 ModestMailOperationPrivate *priv;
1812 ModestTnyFolderRules rules;
1813 XFerMsgAsyncHelper *helper;
1815 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1816 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1817 g_return_if_fail (name);
1819 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1821 /* Get account and set it into mail_operation */
1822 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1824 /* Check folder rules */
1825 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1826 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1827 /* Set status failed and set an error */
1828 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1829 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1830 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1831 _("FIXME: unable to rename"));
1833 /* Notify about operation end */
1834 modest_mail_operation_notify_end (self);
1835 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1836 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1837 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1838 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1839 _("FIXME: unable to rename"));
1840 /* Notify about operation end */
1841 modest_mail_operation_notify_end (self);
1843 TnyFolderStore *into;
1845 into = tny_folder_get_folder_store (folder);
1847 /* Check that the new folder name is not used by any
1848 special local folder */
1849 if (new_name_valid_if_local_account (priv, into, name)) {
1850 /* Create the helper */
1851 helper = g_slice_new0 (XFerMsgAsyncHelper);
1852 helper->mail_op = g_object_ref(self);
1853 helper->dest_folder = NULL;
1854 helper->headers = NULL;
1855 helper->user_callback = NULL;
1856 helper->user_data = NULL;
1858 /* Rename. Camel handles folder subscription/unsubscription */
1859 tny_folder_copy_async (folder, into, name, TRUE,
1861 transfer_folder_status_cb,
1864 modest_mail_operation_notify_end (self);
1866 g_object_unref (into);
1870 /* ******************************************************************* */
1871 /* ************************** MSG ACTIONS ************************* */
1872 /* ******************************************************************* */
1874 void modest_mail_operation_get_msg (ModestMailOperation *self,
1876 GetMsgAsyncUserCallback user_callback,
1879 GetMsgAsyncHelper *helper = NULL;
1881 ModestMailOperationPrivate *priv;
1883 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1884 g_return_if_fail (TNY_IS_HEADER (header));
1886 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1887 folder = tny_header_get_folder (header);
1889 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1891 /* Get message from folder */
1893 /* Get account and set it into mail_operation */
1894 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1896 helper = g_slice_new0 (GetMsgAsyncHelper);
1897 helper->mail_op = self;
1898 helper->user_callback = user_callback;
1899 helper->user_data = user_data;
1900 helper->header = g_object_ref (header);
1902 // The callback's reference so that the mail op is not
1903 // finalized until the async operation is completed even if
1904 // the user canceled the request meanwhile.
1905 g_object_ref (G_OBJECT (helper->mail_op));
1907 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1909 g_object_unref (G_OBJECT (folder));
1911 /* Set status failed and set an error */
1912 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1913 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1914 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1915 _("Error trying to get a message. No folder found for header"));
1917 /* Notify the queue */
1918 modest_mail_operation_notify_end (self);
1923 idle_get_mime_part_size_cb (gpointer userdata)
1925 GetMimePartSizeInfo *idle_info;
1927 idle_info = (GetMimePartSizeInfo *) userdata;
1929 gdk_threads_enter ();
1930 idle_info->callback (idle_info->mail_op,
1932 idle_info->userdata);
1933 gdk_threads_leave ();
1935 g_object_unref (idle_info->mail_op);
1936 g_slice_free (GetMimePartSizeInfo, idle_info);
1942 get_mime_part_size_thread (gpointer thr_user_data)
1944 GetMimePartSizeInfo *info;
1945 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1949 ModestMailOperationPrivate *priv;
1951 info = (GetMimePartSizeInfo *) thr_user_data;
1952 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1954 stream = tny_camel_mem_stream_new ();
1955 tny_mime_part_decode_to_stream (info->mime_part, stream);
1956 tny_stream_reset (stream);
1957 if (tny_stream_is_eos (stream)) {
1958 tny_stream_close (stream);
1959 stream = tny_mime_part_get_stream (info->mime_part);
1962 while (!tny_stream_is_eos (stream)) {
1963 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1964 total += readed_size;
1967 if (info->callback) {
1968 GetMimePartSizeInfo *idle_info;
1970 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1971 idle_info->mail_op = g_object_ref (info->mail_op);
1972 idle_info->size = total;
1973 idle_info->callback = info->callback;
1974 idle_info->userdata = info->userdata;
1975 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1978 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1980 g_object_unref (info->mail_op);
1981 g_object_unref (stream);
1982 g_object_unref (info->mime_part);
1983 g_slice_free (GetMimePartSizeInfo, info);
1989 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1991 GetMimePartSizeCallback user_callback,
1993 GDestroyNotify notify)
1995 GetMimePartSizeInfo *info;
1996 ModestMailOperationPrivate *priv;
1999 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2000 g_return_if_fail (TNY_IS_MIME_PART (part));
2002 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2004 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2005 info = g_slice_new0 (GetMimePartSizeInfo);
2006 info->mail_op = g_object_ref (self);
2007 info->mime_part = g_object_ref (part);
2008 info->callback = user_callback;
2009 info->userdata = user_data;
2011 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2016 get_msg_cb (TnyFolder *folder,
2022 GetMsgAsyncHelper *helper = NULL;
2023 ModestMailOperation *self = NULL;
2024 ModestMailOperationPrivate *priv = NULL;
2026 helper = (GetMsgAsyncHelper *) user_data;
2027 g_return_if_fail (helper != NULL);
2028 self = helper->mail_op;
2029 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2030 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2032 /* Check errors and cancel */
2034 priv->error = g_error_copy (*error);
2035 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2036 } else if (cancelled) {
2037 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2038 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2039 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2040 _("Error trying to refresh the contents of %s"),
2041 tny_folder_get_name (folder));
2043 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2046 /* If user defined callback function was defined, call it even
2047 if the operation failed*/
2048 if (helper->user_callback) {
2049 /* This callback is called into an iddle by tinymail,
2050 and idles are not in the main lock */
2051 gdk_threads_enter ();
2052 helper->user_callback (self, helper->header, msg, helper->user_data);
2053 gdk_threads_leave ();
2056 /* Notify about operation end */
2057 modest_mail_operation_notify_end (self);
2059 g_object_unref (helper->mail_op);
2060 g_object_unref (helper->header);
2061 g_slice_free (GetMsgAsyncHelper, helper);
2066 get_msg_status_cb (GObject *obj,
2070 GetMsgAsyncHelper *helper = NULL;
2071 ModestMailOperation *self;
2072 ModestMailOperationPrivate *priv;
2073 ModestMailOperationState *state;
2075 g_return_if_fail (status != NULL);
2076 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2078 helper = (GetMsgAsyncHelper *) user_data;
2079 g_return_if_fail (helper != NULL);
2081 self = helper->mail_op;
2082 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2087 state = modest_mail_operation_clone_state (self);
2088 state->bytes_done = status->position;
2089 state->bytes_total = status->of_total;
2090 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2091 gdk_threads_enter ();
2093 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2094 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2095 gdk_threads_leave ();
2097 g_slice_free (ModestMailOperationState, state);
2100 /****************************************************/
2102 ModestMailOperation *mail_op;
2104 GetMsgAsyncUserCallback user_callback;
2106 GDestroyNotify notify;
2110 GetMsgAsyncUserCallback user_callback;
2114 ModestMailOperation *mail_op;
2115 } NotifyGetMsgsInfo;
2119 * Used by get_msgs_full_thread to call the user_callback for each
2120 * message that has been read
2123 notify_get_msgs_full (gpointer data)
2125 NotifyGetMsgsInfo *info;
2127 info = (NotifyGetMsgsInfo *) data;
2129 /* Call the user callback. Idles are not in the main lock, so
2131 gdk_threads_enter ();
2132 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2133 gdk_threads_leave ();
2135 g_slice_free (NotifyGetMsgsInfo, info);
2141 * Used by get_msgs_full_thread to free al the thread resources and to
2142 * call the destroy function for the passed user_data
2145 get_msgs_full_destroyer (gpointer data)
2147 GetFullMsgsInfo *info;
2149 info = (GetFullMsgsInfo *) data;
2152 gdk_threads_enter ();
2153 info->notify (info->user_data);
2154 gdk_threads_leave ();
2158 g_object_unref (info->headers);
2159 g_slice_free (GetFullMsgsInfo, info);
2165 get_msgs_full_thread (gpointer thr_user_data)
2167 GetFullMsgsInfo *info;
2168 ModestMailOperationPrivate *priv = NULL;
2169 TnyIterator *iter = NULL;
2171 info = (GetFullMsgsInfo *) thr_user_data;
2172 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2174 iter = tny_list_create_iterator (info->headers);
2175 while (!tny_iterator_is_done (iter)) {
2179 header = TNY_HEADER (tny_iterator_get_current (iter));
2180 folder = tny_header_get_folder (header);
2182 /* Get message from folder */
2185 /* The callback will call it per each header */
2186 msg = tny_folder_get_msg (folder, header, &(priv->error));
2189 ModestMailOperationState *state;
2194 /* notify progress */
2195 state = modest_mail_operation_clone_state (info->mail_op);
2196 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2197 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2198 pair, (GDestroyNotify) modest_pair_free);
2200 /* The callback is the responsible for
2201 freeing the message */
2202 if (info->user_callback) {
2203 NotifyGetMsgsInfo *info_notify;
2204 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2205 info_notify->user_callback = info->user_callback;
2206 info_notify->mail_op = info->mail_op;
2207 info_notify->header = g_object_ref (header);
2208 info_notify->msg = g_object_ref (msg);
2209 info_notify->user_data = info->user_data;
2210 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2211 notify_get_msgs_full,
2214 g_object_unref (msg);
2217 /* Set status failed and set an error */
2218 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2219 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2220 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2221 "Error trying to get a message. No folder found for header");
2223 g_object_unref (header);
2224 tny_iterator_next (iter);
2227 /* Set operation status */
2228 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2229 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2231 /* Notify about operation end */
2232 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2234 /* Free thread resources. Will be called after all previous idles */
2235 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2241 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2242 TnyList *header_list,
2243 GetMsgAsyncUserCallback user_callback,
2245 GDestroyNotify notify)
2247 TnyHeader *header = NULL;
2248 TnyFolder *folder = NULL;
2250 ModestMailOperationPrivate *priv = NULL;
2251 GetFullMsgsInfo *info = NULL;
2252 gboolean size_ok = TRUE;
2254 TnyIterator *iter = NULL;
2256 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2258 /* Init mail operation */
2259 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2260 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2262 priv->total = tny_list_get_length(header_list);
2264 /* Get account and set it into mail_operation */
2265 if (tny_list_get_length (header_list) >= 1) {
2266 iter = tny_list_create_iterator (header_list);
2267 header = TNY_HEADER (tny_iterator_get_current (iter));
2268 folder = tny_header_get_folder (header);
2269 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2270 g_object_unref (header);
2271 g_object_unref (folder);
2273 if (tny_list_get_length (header_list) == 1) {
2274 g_object_unref (iter);
2279 /* Get msg size limit */
2280 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2281 MODEST_CONF_MSG_SIZE_LIMIT,
2284 g_clear_error (&(priv->error));
2285 max_size = G_MAXINT;
2287 max_size = max_size * KB;
2290 /* Check message size limits. If there is only one message
2291 always retrieve it */
2293 while (!tny_iterator_is_done (iter) && size_ok) {
2294 header = TNY_HEADER (tny_iterator_get_current (iter));
2295 if (tny_header_get_message_size (header) >= max_size)
2297 g_object_unref (header);
2298 tny_iterator_next (iter);
2300 g_object_unref (iter);
2304 /* Create the info */
2305 info = g_slice_new0 (GetFullMsgsInfo);
2306 info->mail_op = self;
2307 info->user_callback = user_callback;
2308 info->user_data = user_data;
2309 info->headers = g_object_ref (header_list);
2310 info->notify = notify;
2312 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2314 /* Set status failed and set an error */
2315 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2316 /* FIXME: the error msg is different for pop */
2317 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2318 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2319 _("emev_ni_ui_imap_msg_size_exceed_error"));
2320 /* Remove from queue and free resources */
2321 modest_mail_operation_notify_end (self);
2329 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2330 gboolean remove_to_trash /*ignored*/)
2333 ModestMailOperationPrivate *priv;
2335 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2336 g_return_if_fail (TNY_IS_HEADER (header));
2338 if (remove_to_trash)
2339 g_warning ("remove to trash is not implemented");
2341 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2342 folder = tny_header_get_folder (header);
2344 /* Get account and set it into mail_operation */
2345 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2347 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2350 tny_folder_remove_msg (folder, header, &(priv->error));
2352 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2353 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2355 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2356 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2357 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2358 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2361 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2367 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2369 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2372 g_object_unref (G_OBJECT (folder));
2374 /* Notify about operation end */
2375 modest_mail_operation_notify_end (self);
2379 transfer_msgs_status_cb (GObject *obj,
2383 XFerMsgAsyncHelper *helper = NULL;
2384 ModestMailOperation *self;
2385 ModestMailOperationPrivate *priv;
2386 ModestMailOperationState *state;
2389 g_return_if_fail (status != NULL);
2390 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2392 helper = (XFerMsgAsyncHelper *) user_data;
2393 g_return_if_fail (helper != NULL);
2395 self = helper->mail_op;
2396 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2398 priv->done = status->position;
2399 priv->total = status->of_total;
2401 state = modest_mail_operation_clone_state (self);
2402 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2403 gdk_threads_enter ();
2405 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2406 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2407 gdk_threads_leave ();
2409 g_slice_free (ModestMailOperationState, state);
2414 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2416 XFerMsgAsyncHelper *helper;
2417 ModestMailOperation *self;
2418 ModestMailOperationPrivate *priv;
2420 helper = (XFerMsgAsyncHelper *) user_data;
2421 self = helper->mail_op;
2423 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2426 priv->error = g_error_copy (*err);
2428 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2429 } else if (cancelled) {
2430 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2431 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2432 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2433 _("Error trying to refresh the contents of %s"),
2434 tny_folder_get_name (folder));
2437 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2440 /* Notify about operation end */
2441 modest_mail_operation_notify_end (self);
2443 /* If user defined callback function was defined, call it */
2444 if (helper->user_callback) {
2445 gdk_threads_enter ();
2446 helper->user_callback (priv->source, helper->user_data);
2447 gdk_threads_leave ();
2451 g_object_unref (helper->headers);
2452 g_object_unref (helper->dest_folder);
2453 g_object_unref (helper->mail_op);
2454 g_slice_free (XFerMsgAsyncHelper, helper);
2455 g_object_unref (folder);
2460 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2463 gboolean delete_original,
2464 XferMsgsAsynUserCallback user_callback,
2467 ModestMailOperationPrivate *priv;
2469 TnyFolder *src_folder;
2470 XFerMsgAsyncHelper *helper;
2472 ModestTnyFolderRules rules;
2473 const gchar *id1 = NULL;
2474 const gchar *id2 = NULL;
2475 gboolean same_folder = FALSE;
2477 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2478 g_return_if_fail (TNY_IS_LIST (headers));
2479 g_return_if_fail (TNY_IS_FOLDER (folder));
2481 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2484 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2486 /* Apply folder rules */
2487 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2488 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2489 /* Set status failed and set an error */
2490 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2491 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2492 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2493 _CS("ckct_ib_unable_to_paste_here"));
2494 /* Notify the queue */
2495 modest_mail_operation_notify_end (self);
2499 /* Get source folder */
2500 iter = tny_list_create_iterator (headers);
2501 header = TNY_HEADER (tny_iterator_get_current (iter));
2502 src_folder = tny_header_get_folder (header);
2503 g_object_unref (header);
2504 g_object_unref (iter);
2506 /* Check folder source and destination */
2507 id1 = tny_folder_get_id (src_folder);
2508 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2509 same_folder = !g_ascii_strcasecmp (id1, id2);
2511 /* Set status failed and set an error */
2512 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2513 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2514 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
2515 _("mcen_ib_unable_to_copy_samefolder"));
2517 /* Notify the queue */
2518 modest_mail_operation_notify_end (self);
2521 g_object_unref (src_folder);
2525 /* Create the helper */
2526 helper = g_slice_new0 (XFerMsgAsyncHelper);
2527 helper->mail_op = g_object_ref(self);
2528 helper->dest_folder = g_object_ref(folder);
2529 helper->headers = g_object_ref(headers);
2530 helper->user_callback = user_callback;
2531 helper->user_data = user_data;
2533 /* Get account and set it into mail_operation */
2534 priv->account = modest_tny_folder_get_account (src_folder);
2536 /* Transfer messages */
2537 tny_folder_transfer_msgs_async (src_folder,
2542 transfer_msgs_status_cb,
2548 on_refresh_folder (TnyFolder *folder,
2553 RefreshAsyncHelper *helper = NULL;
2554 ModestMailOperation *self = NULL;
2555 ModestMailOperationPrivate *priv = NULL;
2557 helper = (RefreshAsyncHelper *) user_data;
2558 self = helper->mail_op;
2559 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2562 priv->error = g_error_copy (*error);
2563 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2568 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2569 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2570 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2571 _("Error trying to refresh the contents of %s"),
2572 tny_folder_get_name (folder));
2576 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2578 /* Call user defined callback, if it exists */
2579 if (helper->user_callback) {
2580 gdk_threads_enter ();
2581 helper->user_callback (self, folder, helper->user_data);
2582 gdk_threads_leave ();
2586 /* g_object_unref (helper->mail_op); */
2587 g_slice_free (RefreshAsyncHelper, helper);
2589 /* Notify about operation end */
2590 modest_mail_operation_notify_end (self);
2594 on_refresh_folder_status_update (GObject *obj,
2598 RefreshAsyncHelper *helper = NULL;
2599 ModestMailOperation *self = NULL;
2600 ModestMailOperationPrivate *priv = NULL;
2601 ModestMailOperationState *state;
2603 g_return_if_fail (user_data != NULL);
2604 g_return_if_fail (status != NULL);
2605 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2607 helper = (RefreshAsyncHelper *) user_data;
2608 self = helper->mail_op;
2609 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2611 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2613 priv->done = status->position;
2614 priv->total = status->of_total;
2616 state = modest_mail_operation_clone_state (self);
2617 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2618 gdk_threads_enter ();
2620 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2621 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2622 gdk_threads_leave ();
2624 g_slice_free (ModestMailOperationState, state);
2628 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2630 RefreshAsyncUserCallback user_callback,
2633 ModestMailOperationPrivate *priv = NULL;
2634 RefreshAsyncHelper *helper = NULL;
2636 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2638 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2640 /* Get account and set it into mail_operation */
2641 priv->account = modest_tny_folder_get_account (folder);
2643 /* Create the helper */
2644 helper = g_slice_new0 (RefreshAsyncHelper);
2645 helper->mail_op = g_object_ref (self);
2646 helper->user_callback = user_callback;
2647 helper->user_data = user_data;
2649 /* Refresh the folder. TODO: tinymail could issue a status
2650 updates before the callback call then this could happen. We
2651 must review the design */
2652 tny_folder_refresh_async (folder,
2654 on_refresh_folder_status_update,
2660 * It's used by the mail operation queue to notify the observers
2661 * attached to that signal that the operation finished. We need to use
2662 * that because tinymail does not give us the progress of a given
2663 * operation when it finishes (it directly calls the operation
2667 modest_mail_operation_notify_end (ModestMailOperation *self)
2669 ModestMailOperationState *state;
2670 ModestMailOperationPrivate *priv = NULL;
2672 g_return_if_fail (self);
2674 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2676 /* Set the account back to not busy */
2677 if (priv->account_name) {
2678 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2679 priv->account_name, FALSE);
2680 g_free(priv->account_name);
2681 priv->account_name = NULL;
2684 /* Notify the observers about the mail operation end */
2685 /* We do not wrapp this emission because we assume that this
2686 function is always called from within the main lock */
2687 state = modest_mail_operation_clone_state (self);
2688 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2689 g_slice_free (ModestMailOperationState, state);