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
420 tny_account_cancel (priv->account);
426 modest_mail_operation_get_task_done (ModestMailOperation *self)
428 ModestMailOperationPrivate *priv;
430 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
432 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
437 modest_mail_operation_get_task_total (ModestMailOperation *self)
439 ModestMailOperationPrivate *priv;
441 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
443 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
448 modest_mail_operation_is_finished (ModestMailOperation *self)
450 ModestMailOperationPrivate *priv;
451 gboolean retval = FALSE;
453 if (!MODEST_IS_MAIL_OPERATION (self)) {
454 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
458 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
460 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
461 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
462 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
463 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
473 modest_mail_operation_get_id (ModestMailOperation *self)
475 ModestMailOperationPrivate *priv;
477 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
479 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
484 modest_mail_operation_set_id (ModestMailOperation *self,
487 ModestMailOperationPrivate *priv;
489 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
491 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
496 * Creates an image of the current state of a mail operation, the
497 * caller must free it
499 static ModestMailOperationState *
500 modest_mail_operation_clone_state (ModestMailOperation *self)
502 ModestMailOperationState *state;
503 ModestMailOperationPrivate *priv;
505 /* FIXME: this should be fixed properly
507 * in some cases, priv was NULL, so checking here to
510 g_return_val_if_fail (self, NULL);
511 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
512 g_return_val_if_fail (priv, NULL);
517 state = g_slice_new (ModestMailOperationState);
519 state->status = priv->status;
520 state->op_type = priv->op_type;
521 state->done = priv->done;
522 state->total = priv->total;
523 state->finished = modest_mail_operation_is_finished (self);
524 state->bytes_done = 0;
525 state->bytes_total = 0;
530 /* ******************************************************************* */
531 /* ************************** SEND ACTIONS ************************* */
532 /* ******************************************************************* */
535 modest_mail_operation_send_mail (ModestMailOperation *self,
536 TnyTransportAccount *transport_account,
539 TnySendQueue *send_queue = NULL;
540 ModestMailOperationPrivate *priv;
542 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
543 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
544 g_return_if_fail (TNY_IS_MSG (msg));
546 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
548 /* Get account and set it into mail_operation */
549 priv->account = g_object_ref (transport_account);
553 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
554 if (!TNY_IS_SEND_QUEUE(send_queue)) {
555 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
556 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
557 "modest: could not find send queue for account\n");
559 /* TODO: connect to the msg-sent in order to know when
560 the mail operation is finished */
561 tny_send_queue_add (send_queue, msg, &(priv->error));
562 /* TODO: we're setting always success, do the check in
564 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
567 /* TODO: do this in the handler of the "msg-sent"
568 signal.Notify about operation end */
569 modest_mail_operation_notify_end (self);
573 idle_create_msg_cb (gpointer idle_data)
575 CreateMsgIdleInfo *info = (CreateMsgIdleInfo *) idle_data;
577 gdk_threads_enter ();
578 info->callback (info->mail_op, info->msg, info->userdata);
579 gdk_threads_leave ();
580 g_object_unref (info->mail_op);
582 g_object_unref (info->msg);
583 g_slice_free (CreateMsgIdleInfo, info);
589 create_msg_thread (gpointer thread_data)
591 CreateMsgInfo *info = (CreateMsgInfo *) thread_data;
592 TnyMsg *new_msg = NULL;
593 ModestMailOperationPrivate *priv;
595 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
596 if (info->html_body == NULL) {
597 new_msg = modest_tny_msg_new (info->to, info->from, info->cc,
598 info->bcc, info->subject, info->plain_body,
599 info->attachments_list); /* FIXME: attachments */
601 new_msg = modest_tny_msg_new_html_plain (info->to, info->from, info->cc,
602 info->bcc, info->subject, info->html_body,
603 info->plain_body, info->attachments_list);
608 /* Set priority flags in message */
609 header = tny_msg_get_header (new_msg);
610 if (info->priority_flags != 0)
611 tny_header_set_flags (header, info->priority_flags);
612 if (info->attachments_list != NULL) {
613 tny_header_set_flags (header, TNY_HEADER_FLAG_ATTACHMENTS);
615 g_object_unref (G_OBJECT(header));
617 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
618 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
619 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
620 "modest: failed to create a new msg\n");
628 g_free (info->plain_body);
629 g_free (info->html_body);
630 g_free (info->subject);
631 g_list_foreach (info->attachments_list, (GFunc) g_object_unref, NULL);
632 g_list_free (info->attachments_list);
634 if (info->callback) {
635 CreateMsgIdleInfo *idle_info;
636 idle_info = g_slice_new0 (CreateMsgIdleInfo);
637 idle_info->mail_op = info->mail_op;
638 g_object_ref (info->mail_op);
639 idle_info->msg = new_msg;
641 g_object_ref (new_msg);
642 idle_info->callback = info->callback;
643 idle_info->userdata = info->userdata;
644 g_idle_add (idle_create_msg_cb, idle_info);
646 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
649 g_object_unref (info->mail_op);
650 g_slice_free (CreateMsgInfo, info);
655 modest_mail_operation_create_msg (ModestMailOperation *self,
656 const gchar *from, const gchar *to,
657 const gchar *cc, const gchar *bcc,
658 const gchar *subject, const gchar *plain_body,
659 const gchar *html_body,
660 const GList *attachments_list,
661 TnyHeaderFlags priority_flags,
662 ModestMailOperationCreateMsgCallback callback,
665 CreateMsgInfo *info = NULL;
667 info = g_slice_new0 (CreateMsgInfo);
668 info->mail_op = self;
671 info->from = g_strdup (from);
672 info->to = g_strdup (to);
673 info->cc = g_strdup (cc);
674 info->subject = g_strdup (subject);
675 info->plain_body = g_strdup (plain_body);
676 info->html_body = g_strdup (html_body);
677 info->attachments_list = g_list_copy ((GList *) attachments_list);
678 g_list_foreach (info->attachments_list, (GFunc) g_object_ref, NULL);
679 info->priority_flags = priority_flags;
681 info->callback = callback;
682 info->userdata = userdata;
684 g_thread_create (create_msg_thread, info, FALSE, NULL);
689 TnyTransportAccount *transport_account;
694 modest_mail_operation_send_new_mail_cb (ModestMailOperation *self,
698 SendNewMailInfo *info = (SendNewMailInfo *) userdata;
706 /* Call mail operation */
707 modest_mail_operation_send_mail (self, info->transport_account, msg);
709 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
711 if (info->draft_msg != NULL) {
712 header = tny_msg_get_header (info->draft_msg);
713 /* Note: This can fail (with a warning) if the message is not really already in a folder,
714 * because this function requires it to have a UID. */
715 tny_folder_remove_msg (folder, header, NULL);
716 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
717 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
718 g_object_unref (header);
724 g_object_unref (info->draft_msg);
725 if (info->transport_account)
726 g_object_unref (info->transport_account);
727 g_slice_free (SendNewMailInfo, info);
728 modest_mail_operation_notify_end (self);
732 modest_mail_operation_send_new_mail (ModestMailOperation *self,
733 TnyTransportAccount *transport_account,
735 const gchar *from, const gchar *to,
736 const gchar *cc, const gchar *bcc,
737 const gchar *subject, const gchar *plain_body,
738 const gchar *html_body,
739 const GList *attachments_list,
740 TnyHeaderFlags priority_flags)
742 ModestMailOperationPrivate *priv = NULL;
743 SendNewMailInfo *info;
745 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
746 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
748 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
750 /* Check parametters */
752 /* Set status failed and set an error */
753 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
754 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
755 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
756 _("Error trying to send a mail. You need to set at least one recipient"));
759 info = g_slice_new0 (SendNewMailInfo);
760 info->transport_account = transport_account;
761 if (transport_account)
762 g_object_ref (transport_account);
763 info->draft_msg = draft_msg;
765 g_object_ref (draft_msg);
766 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
767 attachments_list, priority_flags,
768 modest_mail_operation_send_new_mail_cb, info);
774 TnyTransportAccount *transport_account;
776 ModestMsgEditWindow *edit_window;
780 modest_mail_operation_save_to_drafts_cb (ModestMailOperation *self,
784 TnyFolder *folder = NULL;
785 TnyHeader *header = NULL;
786 ModestMailOperationPrivate *priv = NULL;
787 SaveToDraftsInfo *info = (SaveToDraftsInfo *) userdata;
789 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
791 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
792 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
793 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
794 "modest: failed to create a new msg\n");
798 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (info->transport_account), TNY_FOLDER_TYPE_DRAFTS);
800 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
801 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
802 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
803 "modest: failed to create a new msg\n");
807 if (info->draft_msg != NULL) {
808 header = tny_msg_get_header (info->draft_msg);
809 /* Remove the old draft expunging it */
810 tny_folder_remove_msg (folder, header, NULL);
811 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
812 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
813 tny_folder_sync (folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
814 g_object_unref (header);
818 tny_folder_add_msg (folder, msg, &(priv->error));
821 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
823 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
825 if (info->edit_window)
826 modest_msg_edit_window_set_draft (info->edit_window, msg);
831 g_object_unref (G_OBJECT(folder));
832 if (info->edit_window)
833 g_object_unref (G_OBJECT(info->edit_window));
835 g_object_unref (G_OBJECT (info->draft_msg));
836 if (info->transport_account)
837 g_object_unref (G_OBJECT(info->transport_account));
838 g_slice_free (SaveToDraftsInfo, info);
840 modest_mail_operation_notify_end (self);
844 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
845 TnyTransportAccount *transport_account,
847 ModestMsgEditWindow *edit_window,
848 const gchar *from, const gchar *to,
849 const gchar *cc, const gchar *bcc,
850 const gchar *subject, const gchar *plain_body,
851 const gchar *html_body,
852 const GList *attachments_list,
853 TnyHeaderFlags priority_flags)
855 ModestMailOperationPrivate *priv = NULL;
856 SaveToDraftsInfo *info = NULL;
858 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
859 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
861 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
863 /* Get account and set it into mail_operation */
864 priv->account = g_object_ref (transport_account);
866 info = g_slice_new0 (SaveToDraftsInfo);
867 info->transport_account = g_object_ref (transport_account);
868 info->draft_msg = draft_msg;
870 g_object_ref (draft_msg);
871 info->edit_window = edit_window;
873 g_object_ref (edit_window);
875 modest_mail_operation_create_msg (self, from, to, cc, bcc, subject, plain_body, html_body,
876 attachments_list, priority_flags,
877 modest_mail_operation_save_to_drafts_cb, info);
883 ModestMailOperation *mail_op;
884 TnyStoreAccount *account;
885 TnyTransportAccount *transport_account;
888 gchar *retrieve_type;
890 UpdateAccountCallback callback;
897 ModestMailOperation *mail_op;
898 TnyMimePart *mime_part;
900 GetMimePartSizeCallback callback;
902 } GetMimePartSizeInfo;
904 /***** I N T E R N A L F O L D E R O B S E R V E R *****/
905 /* We use this folder observer to track the headers that have been
906 * added to a folder */
909 TnyList *new_headers;
910 } InternalFolderObserver;
914 } InternalFolderObserverClass;
916 static void tny_folder_observer_init (TnyFolderObserverIface *idace);
918 G_DEFINE_TYPE_WITH_CODE (InternalFolderObserver,
919 internal_folder_observer,
921 G_IMPLEMENT_INTERFACE(TNY_TYPE_FOLDER_OBSERVER, tny_folder_observer_init));
925 foreach_add_item (gpointer header, gpointer user_data)
927 tny_list_prepend (TNY_LIST (user_data),
928 g_object_ref (G_OBJECT (header)));
931 /* This is the method that looks for new messages in a folder */
933 internal_folder_observer_update (TnyFolderObserver *self, TnyFolderChange *change)
935 InternalFolderObserver *derived = (InternalFolderObserver *)self;
937 TnyFolderChangeChanged changed;
939 changed = tny_folder_change_get_changed (change);
941 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
944 /* Get added headers */
945 list = tny_simple_list_new ();
946 tny_folder_change_get_added_headers (change, list);
948 /* Add them to the folder observer */
949 tny_list_foreach (list, foreach_add_item,
950 derived->new_headers);
952 g_object_unref (G_OBJECT (list));
957 internal_folder_observer_init (InternalFolderObserver *self)
959 self->new_headers = tny_simple_list_new ();
962 internal_folder_observer_finalize (GObject *object)
964 InternalFolderObserver *self;
966 self = (InternalFolderObserver *) object;
967 g_object_unref (self->new_headers);
969 G_OBJECT_CLASS (internal_folder_observer_parent_class)->finalize (object);
972 tny_folder_observer_init (TnyFolderObserverIface *iface)
974 iface->update_func = internal_folder_observer_update;
977 internal_folder_observer_class_init (InternalFolderObserverClass *klass)
979 GObjectClass *object_class;
981 internal_folder_observer_parent_class = g_type_class_peek_parent (klass);
982 object_class = (GObjectClass*) klass;
983 object_class->finalize = internal_folder_observer_finalize;
989 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
992 TnyList *folders = tny_simple_list_new ();
994 tny_folder_store_get_folders (store, folders, query, NULL);
995 iter = tny_list_create_iterator (folders);
997 while (!tny_iterator_is_done (iter)) {
999 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
1001 tny_list_prepend (all_folders, G_OBJECT (folder));
1002 recurse_folders (folder, query, all_folders);
1003 g_object_unref (G_OBJECT (folder));
1005 tny_iterator_next (iter);
1007 g_object_unref (G_OBJECT (iter));
1008 g_object_unref (G_OBJECT (folders));
1012 * Issues the "progress-changed" signal. The timer won't be removed,
1013 * so you must call g_source_remove to stop the signal emission
1016 idle_notify_progress (gpointer data)
1018 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1019 ModestMailOperationState *state;
1021 state = modest_mail_operation_clone_state (mail_op);
1022 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1023 gdk_threads_enter ();
1025 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1026 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1027 gdk_threads_leave ();
1029 g_slice_free (ModestMailOperationState, state);
1035 * Issues the "progress-changed" signal and removes the timer. It uses
1036 * a lock to ensure that the progress information of the mail
1037 * operation is not modified while there are notifications pending
1040 idle_notify_progress_once (gpointer data)
1044 pair = (ModestPair *) data;
1046 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1047 gdk_threads_enter ();
1049 g_signal_emit (G_OBJECT (pair->first), signals[PROGRESS_CHANGED_SIGNAL], 0, pair->second, NULL);
1050 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1051 gdk_threads_leave ();
1054 /* Free the state and the reference to the mail operation */
1055 g_slice_free (ModestMailOperationState, (ModestMailOperationState*)pair->second);
1056 g_object_unref (pair->first);
1062 * Used to notify the queue from the main
1063 * loop. We call it inside an idle call to achieve that
1066 idle_notify_queue (gpointer data)
1068 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1070 /* Do not need to block, the notify end will do it for us */
1071 modest_mail_operation_notify_end (mail_op);
1072 g_object_unref (mail_op);
1078 compare_headers_by_date (gconstpointer a,
1081 TnyHeader **header1, **header2;
1082 time_t sent1, sent2;
1084 header1 = (TnyHeader **) a;
1085 header2 = (TnyHeader **) b;
1087 sent1 = tny_header_get_date_sent (*header1);
1088 sent2 = tny_header_get_date_sent (*header2);
1090 /* We want the most recent ones (greater time_t) at the
1099 set_last_updated_idle (gpointer data)
1101 gdk_threads_enter ();
1103 /* It does not matter if the time is not exactly the same than
1104 the time when this idle was called, it's just an
1105 approximation and it won't be very different */
1106 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
1108 MODEST_ACCOUNT_LAST_UPDATED,
1112 gdk_threads_leave ();
1118 idle_update_account_cb (gpointer data)
1120 UpdateAccountInfo *idle_info;
1122 idle_info = (UpdateAccountInfo *) data;
1124 gdk_threads_enter ();
1125 idle_info->callback (idle_info->mail_op,
1126 idle_info->new_headers,
1127 idle_info->user_data);
1128 gdk_threads_leave ();
1131 g_object_unref (idle_info->mail_op);
1139 update_account_thread (gpointer thr_user_data)
1141 static gboolean first_time = TRUE;
1142 UpdateAccountInfo *info;
1143 TnyList *all_folders = NULL;
1144 GPtrArray *new_headers = NULL;
1145 TnyIterator *iter = NULL;
1146 TnyFolderStoreQuery *query = NULL;
1147 ModestMailOperationPrivate *priv = NULL;
1148 ModestTnySendQueue *send_queue = NULL;
1149 gint num_new_headers;
1151 info = (UpdateAccountInfo *) thr_user_data;
1152 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
1154 /* Get account and set it into mail_operation */
1155 priv->account = g_object_ref (info->account);
1158 * for POP3, we do a logout-login upon send/receive -- many POP-servers (like Gmail) do not
1159 * show any updates unless we do that
1161 if (!first_time && TNY_IS_CAMEL_POP_STORE_ACCOUNT(priv->account))
1162 tny_camel_pop_store_account_reconnect (TNY_CAMEL_POP_STORE_ACCOUNT(priv->account));
1164 /* Get all the folders. We can do it synchronously because
1165 we're already running in a different thread than the UI */
1166 all_folders = tny_simple_list_new ();
1167 query = tny_folder_store_query_new ();
1168 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1169 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
1174 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1178 iter = tny_list_create_iterator (all_folders);
1179 while (!tny_iterator_is_done (iter)) {
1180 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1182 recurse_folders (folder, query, all_folders);
1183 tny_iterator_next (iter);
1185 g_object_unref (G_OBJECT (iter));
1187 /* Update status and notify. We need to call the notification
1188 with a source function in order to call it from the main
1189 loop. We need that in order not to get into trouble with
1190 Gtk+. We use a timeout in order to provide more status
1191 information, because the sync tinymail call does not
1192 provide it for the moment */
1193 gint timeout = g_timeout_add (100, idle_notify_progress, info->mail_op);
1195 /* Refresh folders */
1196 num_new_headers = 0;
1197 new_headers = g_ptr_array_new ();
1198 iter = tny_list_create_iterator (all_folders);
1200 while (!tny_iterator_is_done (iter) && !priv->error &&
1201 priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1203 InternalFolderObserver *observer;
1204 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
1206 /* Refresh the folder */
1207 /* Our observer receives notification of new emails during folder refreshes,
1208 * so we can use observer->new_headers.
1210 observer = g_object_new (internal_folder_observer_get_type (), NULL);
1211 tny_folder_add_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1213 /* This gets the status information (headers) from the server.
1214 * We use the blocking version, because we are already in a separate
1218 if (!g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES) ||
1219 !g_ascii_strcasecmp (info->retrieve_type, MODEST_ACCOUNT_RETRIEVE_VALUE_MESSAGES_AND_ATTACHMENTS)) {
1222 /* If the retrieve type is full messages, refresh and get the messages */
1223 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
1225 iter = tny_list_create_iterator (observer->new_headers);
1226 while (!tny_iterator_is_done (iter)) {
1227 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1229 /* Apply per-message size limits */
1230 if (tny_header_get_message_size (header) < info->max_size)
1231 g_ptr_array_add (new_headers, g_object_ref (header));
1233 g_object_unref (header);
1234 tny_iterator_next (iter);
1236 g_object_unref (iter);
1238 /* We do not need to do it the first time
1239 because it's automatically done by the tree
1241 if (G_UNLIKELY (!first_time))
1242 tny_folder_poke_status (TNY_FOLDER (folder));
1244 tny_folder_remove_observer (TNY_FOLDER (folder), TNY_FOLDER_OBSERVER (observer));
1245 g_object_unref (observer);
1248 g_object_unref (G_OBJECT (folder));
1250 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1252 tny_iterator_next (iter);
1255 g_object_unref (G_OBJECT (iter));
1256 g_source_remove (timeout);
1258 if (priv->status != MODEST_MAIL_OPERATION_STATUS_CANCELED &&
1259 priv->status != MODEST_MAIL_OPERATION_STATUS_FAILED &&
1260 new_headers->len > 0) {
1264 g_ptr_array_sort (new_headers, (GCompareFunc) compare_headers_by_date);
1266 /* Apply message count limit */
1267 /* If the number of messages exceeds the maximum, ask the
1268 * user to download them all,
1269 * as per the UI spec "Retrieval Limits" section in 4.4:
1271 if (new_headers->len > info->retrieve_limit) {
1272 /* TODO: Ask the user, instead of just
1274 * mail_nc_msg_count_limit_exceeded, with 'Get
1275 * all' and 'Newest only' buttons. */
1276 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1277 MODEST_MAIL_OPERATION_ERROR_RETRIEVAL_NUMBER_LIMIT,
1278 "The number of messages to retrieve exceeds the chosen limit for account %s\n",
1279 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1280 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1285 priv->total = MIN (new_headers->len, info->retrieve_limit);
1286 while (msg_num < priv->total) {
1288 TnyHeader *header = TNY_HEADER (g_ptr_array_index (new_headers, msg_num));
1289 TnyFolder *folder = tny_header_get_folder (header);
1290 TnyMsg *msg = tny_folder_get_msg (folder, header, NULL);
1291 ModestMailOperationState *state;
1295 /* We can not just use the mail operation because the
1296 values of done and total could change before the
1298 state = modest_mail_operation_clone_state (info->mail_op);
1299 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
1300 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
1301 pair, (GDestroyNotify) modest_pair_free);
1303 g_object_unref (msg);
1304 g_object_unref (folder);
1310 /* Get the number of new headers and free them */
1311 num_new_headers = new_headers->len;
1312 g_ptr_array_foreach (new_headers, (GFunc) g_object_unref, NULL);
1313 g_ptr_array_free (new_headers, FALSE);
1315 if (priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED)
1318 /* Perform send (if operation was not cancelled) */
1319 /* priv->op_type = MODEST_MAIL_OPERATION_TYPE_SEND; */
1322 if (priv->account != NULL)
1323 g_object_unref (priv->account);
1324 priv->account = g_object_ref (info->transport_account);
1326 send_queue = modest_runtime_get_send_queue (info->transport_account);
1328 /* timeout = g_timeout_add (250, idle_notify_progress, info->mail_op); */
1329 modest_tny_send_queue_try_to_send (send_queue);
1330 /* g_source_remove (timeout); */
1332 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1333 MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED,
1334 "cannot create a send queue for %s\n",
1335 tny_account_get_name (TNY_ACCOUNT (info->transport_account)));
1336 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1339 /* Check if the operation was a success */
1341 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1343 /* Update the last updated key */
1344 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1345 set_last_updated_idle,
1346 g_strdup (tny_account_get_id (TNY_ACCOUNT (info->account))),
1347 (GDestroyNotify) g_free);
1352 if (info->callback) {
1353 UpdateAccountInfo *idle_info;
1355 /* This thread is not in the main lock */
1356 idle_info = g_malloc0 (sizeof (UpdateAccountInfo));
1357 idle_info->mail_op = g_object_ref (info->mail_op);
1358 idle_info->new_headers = num_new_headers;
1359 idle_info->callback = info->callback;
1360 g_idle_add (idle_update_account_cb, idle_info);
1363 /* Notify about operation end. Note that the info could be
1364 freed before this idle happens, but the mail operation will
1366 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1369 g_object_unref (query);
1370 g_object_unref (all_folders);
1371 g_object_unref (info->account);
1372 g_object_unref (info->transport_account);
1373 g_free (info->retrieve_type);
1374 g_slice_free (UpdateAccountInfo, info);
1382 modest_mail_operation_update_account (ModestMailOperation *self,
1383 const gchar *account_name,
1384 UpdateAccountCallback callback,
1387 GThread *thread = NULL;
1388 UpdateAccountInfo *info = NULL;
1389 ModestMailOperationPrivate *priv = NULL;
1390 ModestAccountMgr *mgr = NULL;
1391 TnyStoreAccount *store_account = NULL;
1392 TnyTransportAccount *transport_account = NULL;
1394 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
1395 g_return_val_if_fail (account_name, FALSE);
1397 /* Init mail operation. Set total and done to 0, and do not
1398 update them, this way the progress objects will know that
1399 we have no clue about the number of the objects */
1400 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1403 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1405 /* Get the Modest account */
1406 store_account = (TnyStoreAccount *)
1407 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
1409 TNY_ACCOUNT_TYPE_STORE);
1411 /* Make sure that we have a connection, and request one
1413 * TODO: Is there some way to trigger this for every attempt to
1414 * use the network? */
1415 if (!modest_platform_connect_and_wait (NULL, TNY_ACCOUNT (store_account)))
1418 if (!store_account) {
1419 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1420 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1421 "cannot get tny store account for %s\n", account_name);
1426 /* Get the transport account, we can not do it in the thread
1427 due to some problems with dbus */
1428 transport_account = (TnyTransportAccount *)
1429 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
1431 if (!transport_account) {
1432 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1433 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1434 "cannot get tny transport account for %s\n", account_name);
1438 /* Create the helper object */
1439 info = g_slice_new (UpdateAccountInfo);
1440 info->mail_op = self;
1441 info->account = store_account;
1442 info->transport_account = transport_account;
1443 info->callback = callback;
1444 info->user_data = user_data;
1446 /* Get the message size limit */
1447 info->max_size = modest_conf_get_int (modest_runtime_get_conf (),
1448 MODEST_CONF_MSG_SIZE_LIMIT, NULL);
1449 if (info->max_size == 0)
1450 info->max_size = G_MAXINT;
1452 info->max_size = info->max_size * KB;
1454 /* Get per-account retrieval type */
1455 mgr = modest_runtime_get_account_mgr ();
1456 info->retrieve_type = modest_account_mgr_get_string (mgr, account_name,
1457 MODEST_ACCOUNT_RETRIEVE, FALSE);
1459 /* Get per-account message amount retrieval limit */
1460 info->retrieve_limit = modest_account_mgr_get_int (mgr, account_name,
1461 MODEST_ACCOUNT_LIMIT_RETRIEVE, FALSE);
1462 if (info->retrieve_limit == 0)
1463 info->retrieve_limit = G_MAXINT;
1465 /* printf ("DEBUG: %s: info->retrieve_limit = %d\n", __FUNCTION__, info->retrieve_limit); */
1467 /* Set account busy */
1468 modest_account_mgr_set_account_busy(mgr, account_name, TRUE);
1469 priv->account_name = g_strdup(account_name);
1471 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
1476 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1478 callback (self, 0, user_data);
1479 modest_mail_operation_notify_end (self);
1483 /* ******************************************************************* */
1484 /* ************************** STORE ACTIONS ************************* */
1485 /* ******************************************************************* */
1489 modest_mail_operation_create_folder (ModestMailOperation *self,
1490 TnyFolderStore *parent,
1493 ModestMailOperationPrivate *priv;
1494 TnyFolder *new_folder = NULL;
1496 TnyList *list = tny_simple_list_new ();
1497 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1499 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
1500 g_return_val_if_fail (name, NULL);
1502 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1504 /* Check for already existing folder */
1505 tny_folder_store_query_add_item (query, name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
1506 tny_folder_store_get_folders (parent, list, query, NULL);
1507 g_object_unref (G_OBJECT (query));
1509 if (tny_list_get_length (list) > 0) {
1510 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1511 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1512 MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS,
1513 _CS("ckdg_ib_folder_already_exists"));
1516 g_object_unref (G_OBJECT (list));
1519 if (TNY_IS_FOLDER (parent)) {
1520 /* Check folder rules */
1521 ModestTnyFolderRules rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1522 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
1523 /* Set status failed and set an error */
1524 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1525 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1526 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1527 _("mail_in_ui_folder_create_error"));
1531 if (!strcmp (name, " ") || strchr (name, '/')) {
1532 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1533 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1534 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1535 _("mail_in_ui_folder_create_error"));
1539 /* Create the folder */
1540 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
1541 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1543 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1546 /* Notify about operation end */
1547 modest_mail_operation_notify_end (self);
1553 modest_mail_operation_remove_folder (ModestMailOperation *self,
1555 gboolean remove_to_trash)
1557 TnyAccount *account;
1558 ModestMailOperationPrivate *priv;
1559 ModestTnyFolderRules rules;
1561 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1562 g_return_if_fail (TNY_IS_FOLDER (folder));
1564 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1566 /* Check folder rules */
1567 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1568 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
1569 /* Set status failed and set an error */
1570 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1571 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1572 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1573 _("mail_in_ui_folder_delete_error"));
1577 /* Get the account */
1578 account = modest_tny_folder_get_account (folder);
1579 priv->account = g_object_ref(account);
1581 /* Delete folder or move to trash */
1582 if (remove_to_trash) {
1583 TnyFolder *trash_folder = NULL;
1584 trash_folder = modest_tny_account_get_special_folder (account,
1585 TNY_FOLDER_TYPE_TRASH);
1586 /* TODO: error_handling */
1587 modest_mail_operation_xfer_folder (self, folder,
1588 TNY_FOLDER_STORE (trash_folder),
1591 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
1593 tny_folder_store_remove_folder (parent, folder, &(priv->error));
1594 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
1597 g_object_unref (G_OBJECT (parent));
1599 g_object_unref (G_OBJECT (account));
1602 /* Notify about operation end */
1603 modest_mail_operation_notify_end (self);
1607 transfer_folder_status_cb (GObject *obj,
1611 ModestMailOperation *self;
1612 ModestMailOperationPrivate *priv;
1613 ModestMailOperationState *state;
1614 XFerMsgAsyncHelper *helper;
1616 g_return_if_fail (status != NULL);
1617 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
1619 helper = (XFerMsgAsyncHelper *) user_data;
1620 g_return_if_fail (helper != NULL);
1622 self = helper->mail_op;
1623 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1625 priv->done = status->position;
1626 priv->total = status->of_total;
1628 state = modest_mail_operation_clone_state (self);
1629 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1630 gdk_threads_enter ();
1632 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
1633 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
1634 gdk_threads_leave ();
1636 g_slice_free (ModestMailOperationState, state);
1641 transfer_folder_cb (TnyFolder *folder,
1642 TnyFolderStore *into,
1644 TnyFolder *new_folder,
1648 XFerMsgAsyncHelper *helper;
1649 ModestMailOperation *self = NULL;
1650 ModestMailOperationPrivate *priv = NULL;
1652 helper = (XFerMsgAsyncHelper *) user_data;
1653 g_return_if_fail (helper != NULL);
1655 self = helper->mail_op;
1656 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1659 priv->error = g_error_copy (*err);
1661 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1662 } else if (cancelled) {
1663 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1664 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1665 MODEST_MAIL_OPERATION_ERROR_OPERATION_CANCELED,
1666 _("Transference of %s was cancelled."),
1667 tny_folder_get_name (folder));
1670 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1673 /* Notify about operation end */
1674 modest_mail_operation_notify_end (self);
1676 /* If user defined callback function was defined, call it */
1677 if (helper->user_callback) {
1678 gdk_threads_enter ();
1679 helper->user_callback (priv->source, helper->user_data);
1680 gdk_threads_leave ();
1684 g_object_unref (helper->mail_op);
1685 g_slice_free (XFerMsgAsyncHelper, helper);
1690 * This function checks if the new name is a valid name for our local
1691 * folders account. The new name could not be the same than then name
1692 * of any of the mandatory local folders
1694 * We can not rely on tinymail because tinymail does not check the
1695 * name of the virtual folders that the account could have in the case
1696 * that we're doing a rename (because it directly calls Camel which
1697 * knows nothing about our virtual folders).
1699 * In the case of an actual copy/move (i.e. move/copy a folder between
1700 * accounts) tinymail uses the tny_folder_store_create_account which
1701 * is reimplemented by our ModestTnyLocalFoldersAccount that indeed
1702 * checks the new name of the folder, so this call in that case
1703 * wouldn't be needed. *But* NOTE that if tinymail changes its
1704 * implementation (if folder transfers within the same account is no
1705 * longer implemented as a rename) this call will allow Modest to work
1708 * If the new name is not valid, this function will set the status to
1709 * failed and will set also an error in the mail operation
1712 new_name_valid_if_local_account (ModestMailOperationPrivate *priv,
1713 TnyFolderStore *into,
1714 const gchar *new_name)
1716 if (TNY_IS_ACCOUNT (into) &&
1717 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (into)) &&
1718 modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (into),
1720 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1721 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1722 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1723 _("FIXME: folder name already in use"));
1730 modest_mail_operation_xfer_folder (ModestMailOperation *self,
1732 TnyFolderStore *parent,
1733 gboolean delete_original,
1734 XferMsgsAsynUserCallback user_callback,
1737 ModestMailOperationPrivate *priv = NULL;
1738 ModestTnyFolderRules parent_rules = 0, rules;
1739 XFerMsgAsyncHelper *helper = NULL;
1741 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1742 g_return_if_fail (TNY_IS_FOLDER (folder));
1744 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1746 /* Get account and set it into mail_operation */
1747 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1748 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1750 /* Get folder rules */
1751 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1752 if (TNY_IS_FOLDER (parent))
1753 parent_rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
1755 /* The moveable restriction is applied also to copy operation */
1756 if ((!TNY_IS_FOLDER_STORE (parent)) || (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE)) {
1757 printf("DEBUG: %s: Not allowing the move.\n", __FUNCTION__);
1758 /* Set status failed and set an error */
1759 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1760 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1761 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1762 _("mail_in_ui_folder_move_target_error"));
1764 /* Notify the queue */
1765 modest_mail_operation_notify_end (self);
1766 } else if (TNY_IS_FOLDER (parent) &&
1767 (parent_rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)) {
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 _("FIXME: parent folder does not accept new folders"));
1774 /* Notify the queue */
1775 modest_mail_operation_notify_end (self);
1779 /* Check that the new folder name is not used by any
1780 special local folder */
1781 if (new_name_valid_if_local_account (priv, parent,
1782 tny_folder_get_name (folder))) {
1783 /* Create the helper */
1784 helper = g_slice_new0 (XFerMsgAsyncHelper);
1785 helper->mail_op = g_object_ref(self);
1786 helper->dest_folder = NULL;
1787 helper->headers = NULL;
1788 helper->user_callback = user_callback;
1789 helper->user_data = user_data;
1791 /* Move/Copy folder */
1792 tny_folder_copy_async (folder,
1794 tny_folder_get_name (folder),
1797 transfer_folder_status_cb,
1800 modest_mail_operation_notify_end (self);
1806 modest_mail_operation_rename_folder (ModestMailOperation *self,
1810 ModestMailOperationPrivate *priv;
1811 ModestTnyFolderRules rules;
1812 XFerMsgAsyncHelper *helper;
1814 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1815 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
1816 g_return_if_fail (name);
1818 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1820 /* Get account and set it into mail_operation */
1821 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1823 /* Check folder rules */
1824 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
1825 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
1826 /* Set status failed and set an error */
1827 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1828 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1829 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1830 _("FIXME: unable to rename"));
1832 /* Notify about operation end */
1833 modest_mail_operation_notify_end (self);
1834 } else if (!strcmp (name, " ") || strchr (name, '/')) {
1835 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1836 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1837 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
1838 _("FIXME: unable to rename"));
1839 /* Notify about operation end */
1840 modest_mail_operation_notify_end (self);
1842 TnyFolderStore *into;
1844 into = tny_folder_get_folder_store (folder);
1846 /* Check that the new folder name is not used by any
1847 special local folder */
1848 if (new_name_valid_if_local_account (priv, into, name)) {
1849 /* Create the helper */
1850 helper = g_slice_new0 (XFerMsgAsyncHelper);
1851 helper->mail_op = g_object_ref(self);
1852 helper->dest_folder = NULL;
1853 helper->headers = NULL;
1854 helper->user_callback = NULL;
1855 helper->user_data = NULL;
1857 /* Rename. Camel handles folder subscription/unsubscription */
1858 tny_folder_copy_async (folder, into, name, TRUE,
1860 transfer_folder_status_cb,
1863 modest_mail_operation_notify_end (self);
1865 g_object_unref (into);
1869 /* ******************************************************************* */
1870 /* ************************** MSG ACTIONS ************************* */
1871 /* ******************************************************************* */
1873 void modest_mail_operation_get_msg (ModestMailOperation *self,
1875 GetMsgAsyncUserCallback user_callback,
1878 GetMsgAsyncHelper *helper = NULL;
1880 ModestMailOperationPrivate *priv;
1882 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1883 g_return_if_fail (TNY_IS_HEADER (header));
1885 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1886 folder = tny_header_get_folder (header);
1888 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1890 /* Get message from folder */
1892 /* Get account and set it into mail_operation */
1893 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
1895 helper = g_slice_new0 (GetMsgAsyncHelper);
1896 helper->mail_op = self;
1897 helper->user_callback = user_callback;
1898 helper->user_data = user_data;
1899 helper->header = g_object_ref (header);
1901 // The callback's reference so that the mail op is not
1902 // finalized until the async operation is completed even if
1903 // the user canceled the request meanwhile.
1904 g_object_ref (G_OBJECT (helper->mail_op));
1906 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1908 g_object_unref (G_OBJECT (folder));
1910 /* Set status failed and set an error */
1911 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1912 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1913 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1914 _("Error trying to get a message. No folder found for header"));
1916 /* Notify the queue */
1917 modest_mail_operation_notify_end (self);
1922 idle_get_mime_part_size_cb (gpointer userdata)
1924 GetMimePartSizeInfo *idle_info;
1926 idle_info = (GetMimePartSizeInfo *) userdata;
1928 gdk_threads_enter ();
1929 idle_info->callback (idle_info->mail_op,
1931 idle_info->userdata);
1932 gdk_threads_leave ();
1934 g_object_unref (idle_info->mail_op);
1935 g_slice_free (GetMimePartSizeInfo, idle_info);
1941 get_mime_part_size_thread (gpointer thr_user_data)
1943 GetMimePartSizeInfo *info;
1944 gchar read_buffer[GET_SIZE_BUFFER_SIZE];
1948 ModestMailOperationPrivate *priv;
1950 info = (GetMimePartSizeInfo *) thr_user_data;
1951 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1953 stream = tny_camel_mem_stream_new ();
1954 tny_mime_part_decode_to_stream (info->mime_part, stream);
1955 tny_stream_reset (stream);
1956 if (tny_stream_is_eos (stream)) {
1957 tny_stream_close (stream);
1958 stream = tny_mime_part_get_stream (info->mime_part);
1961 while (!tny_stream_is_eos (stream)) {
1962 readed_size = tny_stream_read (stream, read_buffer, GET_SIZE_BUFFER_SIZE);
1963 total += readed_size;
1966 if (info->callback) {
1967 GetMimePartSizeInfo *idle_info;
1969 idle_info = g_slice_new0 (GetMimePartSizeInfo);
1970 idle_info->mail_op = g_object_ref (info->mail_op);
1971 idle_info->size = total;
1972 idle_info->callback = info->callback;
1973 idle_info->userdata = info->userdata;
1974 g_idle_add (idle_get_mime_part_size_cb, idle_info);
1977 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
1979 g_object_unref (info->mail_op);
1980 g_object_unref (stream);
1981 g_object_unref (info->mime_part);
1982 g_slice_free (GetMimePartSizeInfo, info);
1988 modest_mail_operation_get_mime_part_size (ModestMailOperation *self,
1990 GetMimePartSizeCallback user_callback,
1992 GDestroyNotify notify)
1994 GetMimePartSizeInfo *info;
1995 ModestMailOperationPrivate *priv;
1998 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1999 g_return_if_fail (TNY_IS_MIME_PART (part));
2001 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2003 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2004 info = g_slice_new0 (GetMimePartSizeInfo);
2005 info->mail_op = g_object_ref (self);
2006 info->mime_part = g_object_ref (part);
2007 info->callback = user_callback;
2008 info->userdata = user_data;
2010 thread = g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2015 get_msg_cb (TnyFolder *folder,
2021 GetMsgAsyncHelper *helper = NULL;
2022 ModestMailOperation *self = NULL;
2023 ModestMailOperationPrivate *priv = NULL;
2025 helper = (GetMsgAsyncHelper *) user_data;
2026 g_return_if_fail (helper != NULL);
2027 self = helper->mail_op;
2028 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2029 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2031 /* Check errors and cancel */
2033 priv->error = g_error_copy (*error);
2034 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2035 } else if (cancelled) {
2036 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2037 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2038 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2039 _("Error trying to refresh the contents of %s"),
2040 tny_folder_get_name (folder));
2042 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2045 /* If user defined callback function was defined, call it even
2046 if the operation failed*/
2047 if (helper->user_callback) {
2048 /* This callback is called into an iddle by tinymail,
2049 and idles are not in the main lock */
2050 gdk_threads_enter ();
2051 helper->user_callback (self, helper->header, msg, helper->user_data);
2052 gdk_threads_leave ();
2055 /* Notify about operation end */
2056 modest_mail_operation_notify_end (self);
2058 g_object_unref (helper->mail_op);
2059 g_object_unref (helper->header);
2060 g_slice_free (GetMsgAsyncHelper, helper);
2065 get_msg_status_cb (GObject *obj,
2069 GetMsgAsyncHelper *helper = NULL;
2070 ModestMailOperation *self;
2071 ModestMailOperationPrivate *priv;
2072 ModestMailOperationState *state;
2074 g_return_if_fail (status != NULL);
2075 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
2077 helper = (GetMsgAsyncHelper *) user_data;
2078 g_return_if_fail (helper != NULL);
2080 self = helper->mail_op;
2081 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2086 state = modest_mail_operation_clone_state (self);
2087 state->bytes_done = status->position;
2088 state->bytes_total = status->of_total;
2089 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2090 gdk_threads_enter ();
2092 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2093 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2094 gdk_threads_leave ();
2096 g_slice_free (ModestMailOperationState, state);
2099 /****************************************************/
2101 ModestMailOperation *mail_op;
2103 GetMsgAsyncUserCallback user_callback;
2105 GDestroyNotify notify;
2109 GetMsgAsyncUserCallback user_callback;
2113 ModestMailOperation *mail_op;
2114 } NotifyGetMsgsInfo;
2118 * Used by get_msgs_full_thread to call the user_callback for each
2119 * message that has been read
2122 notify_get_msgs_full (gpointer data)
2124 NotifyGetMsgsInfo *info;
2126 info = (NotifyGetMsgsInfo *) data;
2128 /* Call the user callback. Idles are not in the main lock, so
2130 gdk_threads_enter ();
2131 info->user_callback (info->mail_op, info->header, info->msg, info->user_data);
2132 gdk_threads_leave ();
2134 g_slice_free (NotifyGetMsgsInfo, info);
2140 * Used by get_msgs_full_thread to free al the thread resources and to
2141 * call the destroy function for the passed user_data
2144 get_msgs_full_destroyer (gpointer data)
2146 GetFullMsgsInfo *info;
2148 info = (GetFullMsgsInfo *) data;
2151 gdk_threads_enter ();
2152 info->notify (info->user_data);
2153 gdk_threads_leave ();
2157 g_object_unref (info->headers);
2158 g_slice_free (GetFullMsgsInfo, info);
2164 get_msgs_full_thread (gpointer thr_user_data)
2166 GetFullMsgsInfo *info;
2167 ModestMailOperationPrivate *priv = NULL;
2168 TnyIterator *iter = NULL;
2170 info = (GetFullMsgsInfo *) thr_user_data;
2171 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
2173 iter = tny_list_create_iterator (info->headers);
2174 while (!tny_iterator_is_done (iter)) {
2178 header = TNY_HEADER (tny_iterator_get_current (iter));
2179 folder = tny_header_get_folder (header);
2181 /* Get message from folder */
2184 /* The callback will call it per each header */
2185 msg = tny_folder_get_msg (folder, header, &(priv->error));
2188 ModestMailOperationState *state;
2193 /* notify progress */
2194 state = modest_mail_operation_clone_state (info->mail_op);
2195 pair = modest_pair_new (g_object_ref (info->mail_op), state, FALSE);
2196 g_idle_add_full (G_PRIORITY_HIGH_IDLE, idle_notify_progress_once,
2197 pair, (GDestroyNotify) modest_pair_free);
2199 /* The callback is the responsible for
2200 freeing the message */
2201 if (info->user_callback) {
2202 NotifyGetMsgsInfo *info_notify;
2203 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
2204 info_notify->user_callback = info->user_callback;
2205 info_notify->mail_op = info->mail_op;
2206 info_notify->header = g_object_ref (header);
2207 info_notify->msg = g_object_ref (msg);
2208 info_notify->user_data = info->user_data;
2209 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2210 notify_get_msgs_full,
2213 g_object_unref (msg);
2216 /* Set status failed and set an error */
2217 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2218 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2219 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2220 "Error trying to get a message. No folder found for header");
2222 g_object_unref (header);
2223 tny_iterator_next (iter);
2226 /* Set operation status */
2227 if (priv->status == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2228 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2230 /* Notify about operation end */
2231 g_idle_add (idle_notify_queue, g_object_ref (info->mail_op));
2233 /* Free thread resources. Will be called after all previous idles */
2234 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
2240 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
2241 TnyList *header_list,
2242 GetMsgAsyncUserCallback user_callback,
2244 GDestroyNotify notify)
2246 TnyHeader *header = NULL;
2247 TnyFolder *folder = NULL;
2249 ModestMailOperationPrivate *priv = NULL;
2250 GetFullMsgsInfo *info = NULL;
2251 gboolean size_ok = TRUE;
2253 TnyIterator *iter = NULL;
2255 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2257 /* Init mail operation */
2258 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2259 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2261 priv->total = tny_list_get_length(header_list);
2263 /* Get account and set it into mail_operation */
2264 if (tny_list_get_length (header_list) >= 1) {
2265 iter = tny_list_create_iterator (header_list);
2266 header = TNY_HEADER (tny_iterator_get_current (iter));
2267 folder = tny_header_get_folder (header);
2268 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2269 g_object_unref (header);
2270 g_object_unref (folder);
2272 if (tny_list_get_length (header_list) == 1) {
2273 g_object_unref (iter);
2278 /* Get msg size limit */
2279 max_size = modest_conf_get_int (modest_runtime_get_conf (),
2280 MODEST_CONF_MSG_SIZE_LIMIT,
2283 g_clear_error (&(priv->error));
2284 max_size = G_MAXINT;
2286 max_size = max_size * KB;
2289 /* Check message size limits. If there is only one message
2290 always retrieve it */
2292 while (!tny_iterator_is_done (iter) && size_ok) {
2293 header = TNY_HEADER (tny_iterator_get_current (iter));
2294 if (tny_header_get_message_size (header) >= max_size)
2296 g_object_unref (header);
2297 tny_iterator_next (iter);
2299 g_object_unref (iter);
2303 /* Create the info */
2304 info = g_slice_new0 (GetFullMsgsInfo);
2305 info->mail_op = self;
2306 info->user_callback = user_callback;
2307 info->user_data = user_data;
2308 info->headers = g_object_ref (header_list);
2309 info->notify = notify;
2311 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
2313 /* Set status failed and set an error */
2314 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2315 /* FIXME: the error msg is different for pop */
2316 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2317 MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT,
2318 _("emev_ni_ui_imap_msg_size_exceed_error"));
2319 /* Remove from queue and free resources */
2320 modest_mail_operation_notify_end (self);
2328 modest_mail_operation_remove_msg (ModestMailOperation *self, TnyHeader *header,
2329 gboolean remove_to_trash /*ignored*/)
2332 ModestMailOperationPrivate *priv;
2334 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2335 g_return_if_fail (TNY_IS_HEADER (header));
2337 if (remove_to_trash)
2338 g_warning ("remove to trash is not implemented");
2340 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2341 folder = tny_header_get_folder (header);
2343 /* Get account and set it into mail_operation */
2344 priv->account = modest_tny_folder_get_account (TNY_FOLDER(folder));
2346 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2349 tny_folder_remove_msg (folder, header, &(priv->error));
2351 tny_header_set_flags (header, TNY_HEADER_FLAG_DELETED);
2352 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
2354 if (TNY_IS_CAMEL_IMAP_FOLDER (folder))
2355 tny_folder_sync(folder, FALSE, &(priv->error)); /* FALSE --> don't expunge */
2356 else if (TNY_IS_CAMEL_POP_FOLDER (folder))
2357 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2360 tny_folder_sync(folder, TRUE, &(priv->error)); /* TRUE --> expunge */
2366 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2368 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2371 g_object_unref (G_OBJECT (folder));
2373 /* Notify about operation end */
2374 modest_mail_operation_notify_end (self);
2378 transfer_msgs_status_cb (GObject *obj,
2382 XFerMsgAsyncHelper *helper = NULL;
2383 ModestMailOperation *self;
2384 ModestMailOperationPrivate *priv;
2385 ModestMailOperationState *state;
2388 g_return_if_fail (status != NULL);
2389 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
2391 helper = (XFerMsgAsyncHelper *) user_data;
2392 g_return_if_fail (helper != NULL);
2394 self = helper->mail_op;
2395 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2397 priv->done = status->position;
2398 priv->total = status->of_total;
2400 state = modest_mail_operation_clone_state (self);
2401 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2402 gdk_threads_enter ();
2404 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2405 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2406 gdk_threads_leave ();
2408 g_slice_free (ModestMailOperationState, state);
2413 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
2415 XFerMsgAsyncHelper *helper;
2416 ModestMailOperation *self;
2417 ModestMailOperationPrivate *priv;
2419 helper = (XFerMsgAsyncHelper *) user_data;
2420 self = helper->mail_op;
2422 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
2425 priv->error = g_error_copy (*err);
2427 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2428 } else if (cancelled) {
2429 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2430 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2431 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2432 _("Error trying to refresh the contents of %s"),
2433 tny_folder_get_name (folder));
2436 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2439 /* Notify about operation end */
2440 modest_mail_operation_notify_end (self);
2442 /* If user defined callback function was defined, call it */
2443 if (helper->user_callback) {
2444 gdk_threads_enter ();
2445 helper->user_callback (priv->source, helper->user_data);
2446 gdk_threads_leave ();
2450 g_object_unref (helper->headers);
2451 g_object_unref (helper->dest_folder);
2452 g_object_unref (helper->mail_op);
2453 g_slice_free (XFerMsgAsyncHelper, helper);
2454 g_object_unref (folder);
2459 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
2462 gboolean delete_original,
2463 XferMsgsAsynUserCallback user_callback,
2466 ModestMailOperationPrivate *priv;
2468 TnyFolder *src_folder;
2469 XFerMsgAsyncHelper *helper;
2471 ModestTnyFolderRules rules;
2472 const gchar *id1 = NULL;
2473 const gchar *id2 = NULL;
2474 gboolean same_folder = FALSE;
2476 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
2477 g_return_if_fail (TNY_IS_LIST (headers));
2478 g_return_if_fail (TNY_IS_FOLDER (folder));
2480 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2483 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2485 /* Apply folder rules */
2486 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
2487 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2488 /* Set status failed and set an error */
2489 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2490 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2491 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
2492 _CS("ckct_ib_unable_to_paste_here"));
2493 /* Notify the queue */
2494 modest_mail_operation_notify_end (self);
2498 /* Get source folder */
2499 iter = tny_list_create_iterator (headers);
2500 header = TNY_HEADER (tny_iterator_get_current (iter));
2501 src_folder = tny_header_get_folder (header);
2502 g_object_unref (header);
2503 g_object_unref (iter);
2505 /* Check folder source and destination */
2506 id1 = tny_folder_get_id (src_folder);
2507 id2 = tny_folder_get_id (TNY_FOLDER(folder));
2508 same_folder = !g_ascii_strcasecmp (id1, id2);
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_BAD_PARAMETER,
2514 _("mcen_ib_unable_to_copy_samefolder"));
2516 /* Notify the queue */
2517 modest_mail_operation_notify_end (self);
2520 g_object_unref (src_folder);
2524 /* Create the helper */
2525 helper = g_slice_new0 (XFerMsgAsyncHelper);
2526 helper->mail_op = g_object_ref(self);
2527 helper->dest_folder = g_object_ref(folder);
2528 helper->headers = g_object_ref(headers);
2529 helper->user_callback = user_callback;
2530 helper->user_data = user_data;
2532 /* Get account and set it into mail_operation */
2533 priv->account = modest_tny_folder_get_account (src_folder);
2535 /* Transfer messages */
2536 tny_folder_transfer_msgs_async (src_folder,
2541 transfer_msgs_status_cb,
2547 on_refresh_folder (TnyFolder *folder,
2552 RefreshAsyncHelper *helper = NULL;
2553 ModestMailOperation *self = NULL;
2554 ModestMailOperationPrivate *priv = NULL;
2556 helper = (RefreshAsyncHelper *) user_data;
2557 self = helper->mail_op;
2558 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2561 priv->error = g_error_copy (*error);
2562 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
2567 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
2568 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
2569 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2570 _("Error trying to refresh the contents of %s"),
2571 tny_folder_get_name (folder));
2575 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
2577 /* Call user defined callback, if it exists */
2578 if (helper->user_callback) {
2579 gdk_threads_enter ();
2580 helper->user_callback (self, folder, helper->user_data);
2581 gdk_threads_leave ();
2585 /* g_object_unref (helper->mail_op); */
2586 g_slice_free (RefreshAsyncHelper, helper);
2588 /* Notify about operation end */
2589 modest_mail_operation_notify_end (self);
2593 on_refresh_folder_status_update (GObject *obj,
2597 RefreshAsyncHelper *helper = NULL;
2598 ModestMailOperation *self = NULL;
2599 ModestMailOperationPrivate *priv = NULL;
2600 ModestMailOperationState *state;
2602 g_return_if_fail (user_data != NULL);
2603 g_return_if_fail (status != NULL);
2604 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
2606 helper = (RefreshAsyncHelper *) user_data;
2607 self = helper->mail_op;
2608 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
2610 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2612 priv->done = status->position;
2613 priv->total = status->of_total;
2615 state = modest_mail_operation_clone_state (self);
2616 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2617 gdk_threads_enter ();
2619 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2620 #ifdef TINYMAIL_IDLES_NOT_LOCKED_YET
2621 gdk_threads_leave ();
2623 g_slice_free (ModestMailOperationState, state);
2627 modest_mail_operation_refresh_folder (ModestMailOperation *self,
2629 RefreshAsyncUserCallback user_callback,
2632 ModestMailOperationPrivate *priv = NULL;
2633 RefreshAsyncHelper *helper = NULL;
2635 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2637 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
2639 /* Get account and set it into mail_operation */
2640 priv->account = modest_tny_folder_get_account (folder);
2642 /* Create the helper */
2643 helper = g_slice_new0 (RefreshAsyncHelper);
2644 helper->mail_op = g_object_ref (self);
2645 helper->user_callback = user_callback;
2646 helper->user_data = user_data;
2648 /* Refresh the folder. TODO: tinymail could issue a status
2649 updates before the callback call then this could happen. We
2650 must review the design */
2651 tny_folder_refresh_async (folder,
2653 on_refresh_folder_status_update,
2659 * It's used by the mail operation queue to notify the observers
2660 * attached to that signal that the operation finished. We need to use
2661 * that because tinymail does not give us the progress of a given
2662 * operation when it finishes (it directly calls the operation
2666 modest_mail_operation_notify_end (ModestMailOperation *self)
2668 ModestMailOperationState *state;
2669 ModestMailOperationPrivate *priv = NULL;
2671 g_return_if_fail (self);
2673 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
2675 /* Set the account back to not busy */
2676 if (priv->account_name) {
2677 modest_account_mgr_set_account_busy (modest_runtime_get_account_mgr(),
2678 priv->account_name, FALSE);
2679 g_free(priv->account_name);
2680 priv->account_name = NULL;
2683 /* Notify the observers about the mail operation end */
2684 /* We do not wrapp this emission because we assume that this
2685 function is always called from within the main lock */
2686 state = modest_mail_operation_clone_state (self);
2687 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, state, NULL);
2688 g_slice_free (ModestMailOperationState, state);